PHP preg_match creating empty arrays - php

I am using the following code:
foreach ($_POST as $key => $value) {
(preg_match("/^._box_(\d+)_5$/", $key, $matches));
//$prodid[] = $matches[1];
$firephp->log($matches, 'matches');
};
This code is working on the following information being $_POSTed from the previous page:
array(
['clin'] =>
['clinmail'] =>
['quest_3'] =>
['quest_7'] =>
['quest_8'] =>
['quest_9'] =>
['quest_10'] =>
['quest_15'] =>
['quest_16'] =>
['hosp'] => 8
['user'] => 16
['a_box_15_5'] => 2
['a_box_16_5'] => 2
['b_box_1_5'] => '$0.00'
['b_box_29_5'] => 1
)
The problem is I get the following result:
matches: array()
matches: array()
matches: array()
matches: array()
matches: array()
matches: array()
matches: array()
matches: array()
matches: array()
matches: array()
matches: array()
matches: array('0'=>'a_box_15_5', '1'=>'15')
matches: array('0'=>'a_box_16_5', '1'=>'16')
matches: array('0'=>'b_box_1_5', '1'=>'1')
matches: array('0'=>'b_box_29_5', '1'=>'29')
I don't want it matching the first 11 positions. I only want the results that actually match what I'm looking for, which in this case is that last four $_POST's isn't that what preg_match is supposed to do? How can I limit it to just the matches?

preg_match() works correctly: if there are no matches, $matches will be empty. But you're not doing anything different if there are no matches, you're always calling $firephp->log(), matches or not.
preg_match() returns 1 if the pattern matches, or 0 otherwise and false if an error occurred, so you can use that to see if there are matches, and only then call $firephp->log():
foreach ($_POST as $key => $value) {
if (preg_match('/^._box_(\d+)_5$/', $key, $matches)) {
$firephp->log($matches, 'matches');
}
}

add check before logging it:
foreach ($_POST as $key => $value) {
(preg_match("/^._box_(\d+)_5$/", $key, $matches));
//$prodid[] = $matches[1];
if(!empty($matches)){
$firephp->log($matches, 'matches');
}
};

Related

How to find specific number in a string php?

I have different strings in which I want to find specific number. If the number is within the string it should print that number.
Strings are like these:
string(9) "path_12.0"
string(9) "path_12.1"
string(9) "path_13.0"
string(9) "path_13.1"
string(9) "path_13.2"
Numbers are like:
int(12)
int(12)
int(13)
int(13)
int(13)
What I tried is:
if (strpos(','.$mainString.',' , ','.$QuestionId.',') != FALSE) {
echo $QuestionId;
} // this doesn't print anything in the body
I also tried the below trick but it also doesn't print anything
if(in_array($QuestionId, explode(',', $mainString))) {
echo $QuestionId;
}
I want to check something like this:
if($questionId is in $mainString) {
echo $questionId;
}
Note: I searched similar questions on StackOverflow but I didn't found a solution which solved my issue, therefore I'm posting this question.
Another option could be to create an array with your strings and use preg_grep with a pattern that checks if the first part of the decimal is equal of one of the numbers.
Example of a pattern where the digits from the array are used as an alternation:
_\K(?:12|13)(?=\.\d+)
_\K Match underscore and forget what was matched
(?: Non capturing group
12|13 Match either 12 or 13
) Close non capturing group
(?=\.\d+) Positive lookahead, assert what is directly on the right is a dot and 1+ digits
For example:
$numbers = [12, 13];
$strings = [
"path_12.0",
"path_12.1",
"path_13.0",
"path_13.1",
"path_13.2",
"path_14.1"
];
$pattern = "/_\K(?:" . implode('|', $numbers) . ")(?=\.\d+)/";
$resullt = preg_grep($pattern, $strings);
print_r($resullt);
Result
Array
(
[0] => path_12.0
[1] => path_12.1
[2] => path_13.0
[3] => path_13.1
[4] => path_13.2
)
Php demo
Or if you want to print the numbers only, you might use array_reduce and collect the matches:
$result = array_reduce($strings, function($carry, $item) use ($pattern){
if (preg_match($pattern, $item, $matches)){
$carry[] = $matches[0];
}
return $carry;
});
print_r($result);
Result
Array
(
[0] => 12
[1] => 12
[2] => 13
[3] => 13
[4] => 13
)
Php demo
You can use below snippet,
$paths = ["path_12.0", "path_12.1", "path_13.0", "path_13.1", "path_13.2", ];
$nos = [12, 12, 13, 13, 13, ];
function strpos_arr($needle,$haystack)
{
if (!is_array($haystack)) {
$haystack = [$haystack];
}
foreach ($haystack as $what) {
if (($pos = strpos($what,(string)$needle)) !== false) {
return $pos;
}
}
return false;
}
foreach ($nos as $key => $value) {
// checking if question id in in path array with str pos
if(strpos_arr($value,$paths) !== false){
echo $value."\n";
}
}
Demo.
$array_strings = ["path_12.0", "path_12.1", "path_13.0", "path_13.1", "path_13.2"];
$array_numbers = [12, 22, 13, 11, 17];
$results = [];
foreach ($array_strings as $string){
preg_match_all('!\d+\.*\d*!', $string, $matches);
foreach ($array_numbers as $number){
if (in_array($number, $matches[0])){
array_push($results, $number);
}
}
}
print_r($results);
results: Array ( [0] => 12 [1] => 13 )
Note 1: array answers can have duplicate values.

use preg_split to split chords and words

I'm working on a little piece of code playing handling song tabs, but i'm stuck on a problem.
I need to parse each song tab line and to split it to get chunks of chords on the one hand, and words in the other.
Each chunk would be like :
$line_chunk = array(
0 => //part of line containing one or several chords
1 => //part of line containing words
);
They should stay "grouped". I mean by this that it should split only when the function reaches the "limit" between chords and words.
I guess I should use preg_split to achieve this. I made some tests, but I've been only able to split on chords, not "groups" of chords:
$line_chunks = preg_split('/(\[[^]]*\])/', $line, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
Those examples shows you what I would like to get :
on a line containing no chords :
$input = '{intro}';
$results = array(
array(
0 => null,
1 => '{intro}
)
);
on a line containing only chords :
$input = '[C#] [Fm] [C#] [Fm] [C#] [Fm]';
$results = array(
array(
0 => '[C#] [Fm] [C#] [Fm] [C#] [Fm]',
1 => null
)
);
on a line containing both :
$input = '[C#]I’m looking for [Fm]you [G#]';
$results = array(
array(
0 => '[C#]',
1 => 'I’m looking for'
),
array(
0 => '[Fm]',
1 => 'you '
),
array(
0 => '[G#]',
1 => null
),
);
Any ideas of how to do this ?
Thanks !
preg_split isn't the way to go. Most of the time, when you have a complicated split task to achieve, it's more easy to try to match what you are interested by instead of trying to split with a not easy to define separator.
A preg_match_all approach:
$pattern = '~ \h*
(?| # open a "branch reset group"
( \[ [^]]+ ] (?: \h* \[ [^]]+ ] )*+ ) # one or more chords in capture group 1
\h*
( [^[\n]* (?<=\S) ) # eventual lyrics (group 2)
| # OR
() # no chords (group 1)
( [^[\n]* [^\s[] ) # lyrics (group 2)
) # close the "branch reset group"
~x';
if (preg_match_all($pattern, $input, $matches, PREG_SET_ORDER)) {
$result = array_map(function($i) { return [$i[1], $i[2]]; }, $matches);
print_r($result);
}
demo
A branch reset group preserves the same group numbering for each branch.
Note: feel free to add:
if (empty($i[1])) $i[1] = null;
if (empty($i[2])) $i[2] = null;
in the map function if you want to obtain null items instead of empty items.
Note2: if you work line by line, you can remove the \n from the pattern.
I would go with PHP explode:
/*
* Process data
*/
$input = '[C#]I’m looking for [Fm]you [G#]';
$parts = explode("[", $input);
$results = array();
foreach ($parts as $item)
{
$pieces = explode("]", $item);
if (count($pieces) < 2)
{
$arrayitem = array( "Chord" => $pieces[0],
"Lyric" => "");
}
else
{
$arrayitem = array( "Chord" => $pieces[0],
"Lyric" => $pieces[1]);
}
$results[] = $arrayitem;
}
/*
* Echo results
*/
foreach ($results as $str)
{
echo "Chord: " . $str["Chord"];
echo "Lyric: " . $str["Lyric"];
}
Boudaries are not tested in the code, as well as remaining whitespaces, but it is a base to work on.

Regex Multiple Capture of Group

I'm using regex to capture the dimensions of ads
Source content is an HTML File, and I'm trying to capture for content that looks like:
size[200x400,300x1200] (could be 1-4 different sizes)
I'm trying to an array with the different sizes in it
My capture code looks like this:
$size_declaration = array();
$sizes = array();
$declaration_pattern = "/size\[(\d{2,4}x\d{2,4}|\d{2,4}x\d{2,4},){1,4}\]/";
$sizes_pattern = "/\d{2,4}x\d{2,4}/";
$result = preg_match($declaration_pattern, $html, $size_declaration);
if( $result ) {
$result = preg_match_all($sizes_pattern, $size_declaration[0], $sizes);
var_dump($sizes);
}
The code above produces usable results:
$sizes = array(
[0] => array (
[0] => '200x400',
[1] => '300x1200'
)
)
but it takes quite a bit of code. I was thinking it was possible to collect the results with a single regex, but I couldn't find a result that works. Is there a way to clean this up a bit?
It's not very practical to turn it into a single expression; it would be better to keep them separate; the first expression finds the boundaries and does rudimentary content checks on the inner contents, the second expression breaks it down into individual pieces:
if (preg_match_all('/size\[([\dx,]+)\]/', $html, $matches)) {
foreach ($matches[0] as $size_declaration) {
if (preg_match_all('/\d+x\d+/', $size_declaration, $sizes)) {
print_r($sizes[0]);
}
}
}
This one is a little simpler:
$html = "size[200x400,300x600,300x100]";
if (($result = preg_match_all("/(\d{2,4}x\d{2,4}){1,4}/", $html, $matches)) > 0)
var_dump($matches);
//
// $matches =>
// array(
// (int) 0 => array(
// (int) 0 => '200x400',
// (int) 1 => '300x600',
// (int) 2 => '300x100'
// ),
// (int) 1 => array(
// (int) 0 => '200x400',
// (int) 1 => '300x600',
// (int) 2 => '300x100'
// )
// )
//
The only way is to repeat the 4 eventual sizes in the pattern:
$subject = <<<LOD
size[523x800]
size[200x400,300x1200]
size[201x300,352x1200,123x456]
size[142x396,1444x32,143x89,231x456]
LOD;
$pattern = '`size\[(\d{2,4}x\d{2,4})(?:,(\d{2,4}x\d{2,4}))?(?:,(\d{2,4}x\d{2,4}))?(?:,(\d{2,4}x\d{2,4}))?]`';
preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
foreach ($matches as &$match) { array_shift($match); }
print_r($matches);
The pattern can also be shorten using references to capture groups:
$pattern = '`size\[(\d{2,4}x\d{2,4})(?:,((?1)))?(?:,((?1)))?(?:,((?1)))?]`';
or with the Oniguruma syntax:
$pattern = '`size\[(\d{2,4}x\d{2,4})(?:,(\g<1>))?(?:,(\g<1>))?(?:,(\g<1>))?]`';

loop through an array and apply preg_match

i need to walk through an multidimensional array and and check ONLY the title if not start with alphabetic , as the follow :
Array
(
[0] => Array
(
[letter] =>
[id] => 176
)
[1] => Array
(
[letter] => "
[id] => 175
)
.....etc
so i need to check only letter if not start with a-zA-z , i have try do that , but still have something missing ,,
$notMatch = array();
foreach ($data as $value) {
foreach ($value as $item['title']=>$d) {
if(!preg_match('/^[a-zA-Z]$/',$d)){
$notMatch[]=$d;
}
}
}
See below URL i think it is very help full to you.
Update:
Using preg_match on a multidimensional array to return key values arrays
Try it
<?php
$data = array(
"abc"=>array(
"label" => "abc",
"value" => "def",
"type" => "ghi",
"desc" => "jkl",
),
"def"=>array(
"label" => "mno",
"value" => "qrs",
"type" => "tuv",
"desc" => "wxyz",
),
);
$matches = array();
$pattern = "/a/i"; //contains an 'a'
//loop through the data
foreach($data as $key=>$value){
//loop through each key under data sub array
foreach($value as $key2=>$value2){
//check for match.
if(preg_match($pattern, $value2)){
//add to matches array.
$matches[$key]=$value;
//match found, so break from foreach
break;
}
}
}
echo '<pre>'.print_r($matches, true).'</pre>';
?>
I removed one foreach loop and changed your preg_match pattern, removed the start of string/line and end of string/line anchors.
This is how I did it:
// I'm assuming your data array looks something like this:
$data = array(array('title'=>'fjsdoijsdiojsd', 'id'=>3),
array('title'=>'oijijsd', 'id'=>5),
array('title'=>'09234032', 'id'=>3));
$notMatch = array();
foreach ($data as $value) {
if(!preg_match('/([a-zA-Z]).*/',$value['title'])){
$notMatch[]=$value['title'];
echo 'notmatch! ' . $value['title'];
}
}
However, it's quite possible that someone with more regex experience can get you a better pattern. :)
http://codepad.viper-7.com/dvUQoW

Turn text inside brackets to an array PHP

If I have a string that looks like this:
$myString = "[sometext][moretext][993][112]This is a long text";
I want it to be turned into:
$string = "This is a long text";
$arrayDigits[0] = 993;
$arrayDigits[1] = 112;
$arrayText[0] = "sometext";
$arrayText[1] = "moretext";
How can I do this with PHP?
I understand Regular Expressions is the solution. Please notice that $myString was just an example. There can be several brackets, not just two of each, as in my example.
Thanks for your help!
This is what I came up with.
<?php
#For better display
header("Content-Type: text/plain");
#The String
$myString = "[sometext][moretext][993][112]This is a long text";
#Initialize the array
$matches = array();
#Fill it with matches. It would populate $matches[1].
preg_match_all("|\[(.+?)\]|", $myString, $matches);
#Remove anything inside of square brackets, and assign to $string.
$string = preg_replace("|\[.+\]|", "", $myString);
#Display the results.
print_r($matches[1]);
print_r($string);
After that, you can iterate over the $matches array and check each value to assign it to a new array.
Try this:
$s = '[sometext][moretext][993][112]This is a long text';
preg_match_all('/\[(\w+)\]/', $s, $m);
$m[1] will contain all texts in the brakets, after this you could check type of each value. Also, you could check this using two preg_match_all: at first time with pattern /\[(\d+)\]/ (will return array of digits), in the second - pattern /\[([a-zA-z]+)\]/ (that will return words):
$s = '[sometext][moretext][993][112]This is a long text';
preg_match_all('/\[(\d+)\]/', $s, $matches);
$arrayOfDigits = $matches[1];
preg_match_all('/\[([a-zA-Z]+)\]/', $s, $matches);
$arrayOfWords = $matches[1];
For cases like yours you can make use of named subpatterns so to "tokenize" your string. With some little code, this can be made easily configurable with an array of tokens:
$subject = "[sometext][moretext][993][112]This is a long text";
$groups = array(
'digit' => '\[\d+]',
'text' => '\[\w+]',
'free' => '.+'
);
Each group contains the subpattern and it's name. They match in their order, so if the group digit matches, it won't give text a chance (which is necessary here because \d+ is a subset of \w+). This array can then turned into a full pattern:
foreach($groups as $name => &$subpattern)
$subpattern = sprintf('(?<%s>%s)', $name, $subpattern);
unset($subpattern);
$pattern = sprintf('/(?:%s)/', implode('|', $groups));
The pattern looks like this:
/(?:(?<digit>\[\d+])|(?<text>\[\w+])|(?<free>.+))/
Everything left to do is to execute it against your string, capture the matches and filter them for some normalized output:
if (preg_match_all($pattern, $subject, $matches))
{
$matches = array_intersect_key($matches, $groups);
$matches = array_map('array_filter', $matches);
$matches = array_map('array_values', $matches);
print_r($matches);
}
The matches are now nicely accessible in an array:
Array
(
[digit] => Array
(
[0] => [993]
[1] => [112]
)
[text] => Array
(
[0] => [sometext]
[1] => [moretext]
)
[free] => Array
(
[0] => This is a long text
)
)
The full example at once:
$subject = "[sometext][moretext][993][112]This is a long text";
$groups = array(
'digit' => '\[\d+]',
'text' => '\[\w+]',
'free' => '.+'
);
foreach($groups as $name => &$subpattern)
$subpattern = sprintf('(?<%s>%s)', $name, $subpattern);
unset($subpattern);
$pattern = sprintf('/(?:%s)/', implode('|', $groups));
if (preg_match_all($pattern, $subject, $matches))
{
$matches = array_intersect_key($matches, $groups);
$matches = array_map('array_filter', $matches);
$matches = array_map('array_values', $matches);
print_r($matches);
}
You could try something along the lines of:
<?php
function parseString($string) {
// identify data in brackets
static $pattern = '#(?:\[)([^\[\]]+)(?:\])#';
// result container
$t = array(
'string' => null,
'digits' => array(),
'text' => array(),
);
$t['string'] = preg_replace_callback($pattern, function($m) use(&$t) {
// shove matched string into digits/text groups
$t[is_numeric($m[1]) ? 'digits' : 'text'][] = $m[1];
// remove the brackets from the text
return '';
}, $string);
return $t;
}
$string = "[sometext][moretext][993][112]This is a long text";
$result = parseString($string);
var_dump($result);
/*
$result === array(
"string" => "This is a long text",
"digits" => array(
993,
112,
),
"text" => array(
"sometext",
"moretext",
),
);
*/
(PHP5.3 - using closures)

Categories