Regex to match certain pattern of number combinations - php

I'm looking making a regex in php that gets data from the following format:
"1,2,3;7,1,3;1" returns an $matches array with "(1,2,3,7,1,3,1)"
"1" returns an $matches with "(1)"
"1;1;3;5;7;10;999" returns an $matches array with "(1,1,3,5,7,10,999)"
"1,1,1;2,5;3,4" doesn't pass since numbers are repeating within semicolon boundaries
"2,3,4;5,;" doesn't pass since it doesn't satisfy the format.
(Quotes in the examples are there to make them easier to read; they should not appear in the real results.)
The format is digit numbers separated by either commas or semicolons and within semicolons they don't repeat each other. It should not accept any other format.
I tried /(^(\d{1,3})$)|(([0-9]+)([,|;]{1}[0-9]+)+)/ but it didn't work.
I also tried /[0-9]+([,|;]{1}[0-9]+)+/ but it didn't worked either. When I got the $matches array it didn't have the values I needed as depicted above.
I'm doing this in PHP 5.2.
Thanks.

This particular problem has too much logic for regular expressions to be practical; this is how you could solve it with regular code:
// reduction function - keeps merging comma separated arguments
// until there's a duplicate or invalid item
function join_unique(&$result, $item)
{
if ($result === false) {
return false;
}
$items = explode(',', $item);
$numbers = array_filter($items, 'is_numeric');
if (count($items) != count($numbers)) {
return false;
}
$unique = array_unique($numbers);
if (count($unique) != count($numbers)) {
return false;
}
return array_merge($result, $numbers);
}
// main function - parse a string of comma / semi-colon separated values
function parse_nrs($str)
{
return array_reduce(explode(';', $str), 'join_unique', array());
}
var_dump(parse_nrs('1,2,3;7,1,3;1'));
var_dump(parse_nrs('1'));
var_dump(parse_nrs('1;1;3;5;7;10;999'));
var_dump(parse_nrs('1,1,1;2,5;3,4'));
var_dump(parse_nrs('2,3,4;5,;'));
Output:
array(7) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[2]=>
string(1) "3"
[3]=>
string(1) "7"
[4]=>
string(1) "1"
[5]=>
string(1) "3"
[6]=>
string(1) "1"
}
array(1) {
[0]=>
string(1) "1"
}
array(7) {
[0]=>
string(1) "1"
[1]=>
string(1) "1"
[2]=>
string(1) "3"
[3]=>
string(1) "5"
[4]=>
string(1) "7"
[5]=>
string(2) "10"
[6]=>
string(3) "999"
}
bool(false)
bool(false)
See also: array_reduce() array_unique()

It is impossible to do this in a single step. First you will need to check for the requirement of numbers repeating within a semicolon boundary, and then if it passes that checks split the string.
For example:
if (!preg_match('/\b(\d+),[^;]*\b\1\b/', $string)) {
$matches = preg_split('/[,;]/', $string);
} else {
$matches = NULL;
}
Ideone: http://ideone.com/Y8xf1N

Related

How to convert array to string in codeigniter?

I am new to PHP.
I want to convert this array;
array(2) {
[0]=> object(stdClass)#24 (1) {
["item"]=> string(1) "2"
}
[1]=> object(stdClass)#25 (1) {
["item"]=> string(1) "1"
}
}
to string like this
string(1) "2", string(2)"1", string(3)"0"...
What is the way to do this?
Note: i try add to "row()" in php code. but always single result.
for example: only string(1)"2"
You are asking something weird. But here is an answer:
let say $arr is your
array(2) { [0]=> object(stdClass)#24 (1) { ["item"]=> string(1) "2" }
[1]=> object(stdClass)#25 (1) { ["item"]=> string(1) "1" } }
then your code to convert it into that string you mentioned will be:
$str=''; $idx=0;
foreach ($arr as $obj) {
$str.=($idx==0?'':', ').'string ('.$idx++.') "'.$obj->item.'"';
}
Now you have your weird string in $str var.
Or if my first weird guess is wrong. Here is another that has more sense to me, but not asked by you:
foreach ($arr as $obj) {
echo $obj->item; // or do whatever you want with this value which is string type
}
Looks you have an array object, you need to use a foreach loop here, and your array values are "2", "1". Not string(1) "2" , string(1) "1", You use a var_dump so the arrays shows with the type and length.
array(2) {
[0]=> object(stdClass)#24 (1) {
["item"]=> string(1) "2"
}
[1]=> object(stdClass)#25 (1) {
["item"]=> string(1) "1"
}
}
To get each value using foreach, see the below example, let your array name is $arr.
foreach($arr as $val){
echo $val->item;
}
This will display the array values as: "2", "1".

Difference between two arrays containing numbers as string

I´ve got a question about compairing two (text)arrays. I obtained two arrays from a loop containing numbers as shown below:
array(96) { [1]=> string(2) "20" [2]=> string(2) "18" [3]=> string(2)...
array(96) { [1]=> string(3) "135" [2]=> string(3) "103" [3]=> string(2) "88"
What I want is a new array which contains the difference of the values (1-2). This means that the 2 arrays above will results in the following new (text)array
array(96) { [1]=> string(3) "-115" [2]=> string(3) "-85" [3]=> string(2)
Can someone help me?
You could do this with one foreach-loop. And then substract them from each other. You just need the same count of elements in $array and in $array2.
$new = array();
foreach($array as $key => $val) {
$new[] = (string) ($val - $array2[$key]);
}
If it doesn't matter if the values are integers, you can remove the type casting (string).
this is a function,
function foo($array1, $array2){
$resultArray = array();
for($i=0; i<count($array1); $i++){
$resultArray[] = (string)((int)$array1[$i] - (int)$array2[$i]);
}
return $resultArray;
}
Hope this will help :)
<?php
$a=array(20,18);
$b=array(135,103);
function fr($d,$d1){
global $c;
$c[]=$d-$d1;
}
array_map('fr',$a,$b);
var_dump($c);

Using OR operator to match the string in php

I am getting past of speech in result. I kept condition to feed noun and adjectives on one array like this:
function printTag($tags) {
$var = array();
foreach($tags as $t) {
echo $t['token'] . "/" . $t['tag'] . " ";
if($t['tag'] == 'NN'|| $t['tag']== 'JJ'){
array_push($var, $t['token']) ;
}
}
return $var;
}
but it does not give correct result:
My out put for echo is this :
The/DT quick/JJ brown/JJ fox/NN
jumped/VBD over/IN the/DT lazy/JJ
dog./NN this/DT is/VBZ really/RB yummy/JJ and/CC excellent/JJ
pizza/NN
I/NN have/VBP seen/VBN have/VBP really/RB in/IN love/NN it/PRP
it/PRP
when I do var_dump($var), it gives:
array(6) {
[0]=>
string(5) "quick"
[1]=>
string(5) "brown"
[2]=>
string(4) "dog."
[3]=>
string(5) "yummy"
[4]=>
string(1) "I"
[5]=>
string(4) "love"
}
why some noun and adjectives skipped?
The reason is that the string you are comparing might have endline or whitespace characters in it.
This can be resolved by using the following:
trim($t['tag']) == 'NN'
This is generally a good idea when comparing strings.

PHP Associative Arrays with Variable Key Names

I am trying to create an associative array with the keys being email addresses and the values being passwords. It is reading from an XML database to get the information. Here is my code:
$data = simplexml_load_file("Treasury.xml");
//Add in all passwords
for ($i = 0; $i < count($data->Member); $i++) {
$key = $data->Member[$i]->Email + '';
$USERS[$key] = $data->Member[$i]->Pin;
}
The problem comes in the for loop. It gets a correct count of the members (I had that print out) but the key is always being labeled as the number 0, resulting in only the last pin being stored in an array on length 1. Is there something syntactically that I am doing wrong?
Thanks in advance.
EDIT: I did a var_dump of the first user in the XML document. Here it is (Sorry for how long it is):
object(SimpleXMLElement)#4 (5) { ["Name"]=> string(19) "Mackenzie Daugherty" ["PC"]=> object(SimpleXMLElement)#2 (0) { } ["Email"]=> string(16) "dau53688#obu.edu" ["Pin"]=> string(4) "0000" ["Payments"]=> object(SimpleXMLElement)#3 (1) { ["Payment"]=> array(2) { [0]=> object(SimpleXMLElement)#5 (7) { ["Type"]=> string(4) "Dues" ["Description"]=> string(18) "Dues for Fall 2013" ["DateIssued"]=> string(7) "8/26/13" ["DateEnd"]=> string(6) "9/9/13" ["Owed"]=> string(2) "55" ["Paid"]=> string(2) "55" ["Plan"]=> object(SimpleXMLElement)#7 (5) { ["InPlan"]=> string(1) "0" ["PlanDescription"]=> object(SimpleXMLElement)#8 (0) { } ["Intervals"]=> string(1) "0" ["Completed"]=> string(1) "0" ["PerInterval"]=> string(1) "0" } } [1]=> object(SimpleXMLElement)#6 (7) { ["Type"]=> string(19) "Tiger Tunes Tickets" ["Description"]=> string(18) "Two Saturday Night" ["DateIssued"]=> string(7) "8/26/13" ["DateEnd"]=> string(7) "8/26/13" ["Owed"]=> string(2) "30" ["Paid"]=> string(2) "30" ["Plan"]=> object(SimpleXMLElement)#7 (5) { ["InPlan"]=> string(1) "0" ["PlanDescription"]=> object(SimpleXMLElement)#8 (0) { } ["Intervals"]=> string(1) "0" ["Completed"]=> string(1) "0" ["PerInterval"]=> string(1) "0" } } } } }
As clearly stated in the documentation that I'm sure you've been studying carefully, the PHP concatenation operator is ., not +.
Your code takes two operands, and attempts to perform arithmetic addition on them. Since they are not [meaningful] numbers, you end up with 0.
(I couldn't give a more detailed assessment without knowing the precise values of your operands, which you did not provide.)
Your code should read:
$key = $data->Member[$i]->Email . '';
// ^
// (is the concatenation necessary at all?
// isn't Email already a string?)
Make the same correction elsewhere.

PHP regex. How to get an array of matches?

I have a string in a format like this:
5;1-x;1-2;(1-x;)+
I used 1-x as a notation for all integers from 1 to infinity and (1-x;)+ to mark that the last integer may be repeated any number of times.
Some example strings:
5;1;1;1
5;7;2;7;5;1;9
How can I match these strings with regex and get all the (1-x;)+ matches?
I have tried the following:
preg_match_all('%5;([1-9]{1}[0-9]*);([1-2]);([1-9]{1}[0-9]*;?)+%',
$str, $matches);
And the result for string "5;1;1;1" is:
array(4) {
[0]=>
array(1) {
[0]=>
string(7) "5;1;1;1"
}
[1]=>
array(1) {
[0]=>
string(1) "1"
}
[2]=>
array(1) {
[0]=>
string(1) "1"
}
[3]=>
array(1) {
[0]=>
string(1) "1"
}
}
For the string "5;7;2;7;5;1;9" it is:
array(4) {
[0]=>
array(1) {
[0]=>
string(13) "5;7;2;7;5;1;9"
}
[1]=>
array(1) {
[0]=>
string(1) "7"
}
[2]=>
array(1) {
[0]=>
string(1) "2"
}
[3]=>
array(1) {
[0]=>
string(1) "9"
}
}
As you can see, only the last integer from (1-x;)+ is in the matches array, but I want the matches array to contain values 7, 5, 1, and 9, not just the last one. Is this even possible using regex or do I need to use another approach to validate and get values from these strings?
One way
//$str = "5;1;1;1";
$str = "5;7;2;7;5;1;9";
$pattern = '%^5;([1-9]\d*;)[12];((?:[1-9]\d*;?)+)$%';
$str = preg_replace( $pattern, '$1$2', $str, -1, $count );
if ( $count ) {
print_r( explode( ';', $str ) );
} else {
echo 'Invalid string';
}
The -1 means no limit to the number of replacements.
$count is the number of replacements made. It will be 1 if the string is valid, or 0 otherwise.
The above assumes a string is still valid if it ends in a ;.
I honestly would just explode the string and remove the unwanted first and third elements that like this:
$array = explode(';', $string);
$diff_array = array(0 => 'not_used', 2 => 'not_used');
$final_array = array_key_diff($array, $diff_array);
This gives you an array of all the values except the first and third elements which are the ones which you seem to not be interested in.
If you then need to verify that the remaining elements are indeed integers with value >= 1 you could run an array_filter on it like this:
$filtered_array = array_filter($final_array, function($value) {
if ((string)(int)$value == $value && (int)$value >= 1) return true;
return false;
}

Categories