preg_match exact number - php

I'm using
$regex = '/'.implode('|', 10).'/i';
preg_match($regex, $ids)
to find the number 10 in a list of IDs ($ids). However, if the list of IDs looks like this:
$ids = array(10, 110, 1010);
Would it bring back all of them? How can I make it find the exact number I am after, and not just find a number that contains the number I'm after?
Thanks.
Edit:
I made a mistake above. The list of IDs is actually a string of comma separated values. For example:
$ids = "10,1010,101";
It's hard to explain the whole idea process behind this, but this is my full code:
<?php
$file = fopen('allprods.csv', 'r');
$id = array($_GET['id']);
$id = array_map('preg_quote', $id);
$regex = '/'.implode('|', $id).'/i';
$skus = array();
while (($line = fgetcsv($file)) !== FALSE) {
list($ids, $sku) = $line;
if(preg_match($regex, $ids)) {
$skus[] = $sku;
}
}
$count = count($skus);
$i = 1;
echo $category_id;
foreach ($skus as $sku){
echo $sku;
if($i != $count) { echo "`"; }
$i++;
}
I'm essentially rooting through a csv that has an ID column (some rows have multiple ids in that column, spearated by commas), and an sku column. More info here
So I need the code to check the string of ids for a certain ID, for example 10, and then add the appropriate SKU to an sku array.
I'm sure this code is a mess, so bear with me while I hack PHP to bits!
Edit: This is now solved! I used in_array instead, as mentioned in the answers. First of all I exploded the comma separate string. Code can be seen below:
$skus = array();
while (($line = fgetcsv($file)) !== FALSE) {
list($ids, $sku) = $line;
$cats = explode(',',$ids);
if (in_array($_GET['id'], $cats)) {
$skus[] = $sku;
}
}
Thanks for the help all.

Don't use a regex for this. Use in_array()
if( in_array(10, $ids) ) {
// do something
}
else {
// not found
}

In regex, if you want to find an exact match rather than just a substring match, you need to use start and end anchors. These are represented in regex by the ^ (start) and $ (end) characters.
So your regex to find "10" and not "110", etc, would be /^10$/.
But if you're looking for a number, why not just use == or in_array()?
PHP is quite capable of evaluating a numeric without having to parse it with regular expressions.

$regex = '/^10$/';
this will only match if the ^ is the beginning of the string, and the $ is the end of the string.

I'd use in_array() as suggested by #Cfreak, but if you want to use regex to match an id of 10 you can do
preg_match('/[^\d]?10[^\d]?/', implode('|', $ids))
If you have array(1,10,1010,010), implode() will change this to 1|10|1010|010 and the pattern will match against '10' not preceded or followed by any other digit (ie. another 0 or 1 as in 0101)

Related

How to find ALL substrings in string using starting and ending words arrays PHP

I've spent my last 4 hours figuring out how to ... I got to ask for your help now.
I'm trying to extract from a text multiple substring match my starting_words_array and ending_words_array.
$str = "Do you see that ? Indeed, I can see that, as well as this." ;
$starting_words_array = array('do','I');
$ending_words_array = array('?',',');
expected output : array ([0] => 'Do you see that ?' [1] => 'I can see that,')
I manage to write a first function that can find the first substring matching one of both arrays items. But i'm not able to find how to loop it in order to get all the substring matching my requirement.
function SearchString($str, $starting_words_array, $ending_words_array ) {
forEach($starting_words_array as $test) {
$pos = strpos($str, $test);
if ($pos===false) continue;
$found = [];
forEach($ending_words_array as $test2) {
$posStart = $pos+strlen($test);
$pos2 = strpos($str, $test2, $posStart);
$found[] = ($pos2!==false) ? $pos2 : INF;
}
$min = min($found);
if ($min !== INF)
return substr($str,$pos,$min-$pos) .$str[$min];
}
return '';
}
Do you guys have any idea about how to achieve such thing ?
I use preg_match for my solution. However, the start and end strings must be escaped with preg_quote. Without that, the solution will be wrong.
function searchString($str, $starting_words_array, $ending_words_array ) {
$resArr = [];
forEach($starting_words_array as $i => $start) {
$end = $ending_words_array[$i] ?? "";
$regEx = '~'.preg_quote($start,"~").".*".preg_quote($end,"~").'~iu';
if(preg_match_all($regEx,$str,$match)){
$resArr[] = $match[0];
}
}
return $resArr;
}
The result is what the questioner expects.
If the expressions can occur more than once, preg_match_all must also be used. The regex must be modify.
function searchString($str, $starting_words_array, $ending_words_array ) {
$resArr = [];
forEach($starting_words_array as $i => $start) {
$end = $ending_words_array[$i] ?? "";
$regEx = '~'.preg_quote($start,"~").".*?".preg_quote($end,"~").'~iu';
if(preg_match_all($regEx,$str,$match)){
$resArr = array_merge($resArr,$match[0]);
}
}
return $resArr;
}
The resut for the second variant:
array (
0 => "Do you see that ?",
1 => "Indeed,",
2 => "I can see that,",
)
I would definitely use regex and preg_match_all(). I won't give you a full working code example here but I will outline the necessary steps.
First, build a regex from your start-end-pairs like that:
$parts = array_map(
function($start, $end) {
return $start . '.+' . $end;
},
$starting_words_array,
$ending_words_array
);
$regex = '/' . join('|', $parts) . '/i';
The /i part means case insensitive search. Some characters like the ? have a special purpose in regex, so you need to extend above function in order to escape it properly.
You can test your final regex here
Then use preg_match_all() to extract your substrings:
preg_match_all($regex, $str, $matches); // $matches is passed by reference, no need to declare it first
print_r($matches);
The exact structure of your $matches array will be slightly different from what you asked for but you will be able to extract your desired data from it
Benni answer is best way to go - but let just point out the problem in your code if you want to fix those:
strpos is not case sensitive and find also part of words so you need to changes your $starting_words_array = array('do','I'); to $starting_words_array = array('Do','I ');
When finding a substring you use return which exit the function so you want find any other substring. In order to fix that you can define $res = []; at the beginning of the function and replace return substr($str,$pos,... with $res[] = substr($str,$pos,... and at the end return the $res var.
You can see example in 3v4l - in that example you get the output you wanted

Trying to get lowest value before comma from string using explode

I am new to php but learning fast. I am trying to extract the lowest price from a string of values like -
"12/6/2020:Some Text:345.44,13/6/2020:Some Text:375.88,14/6/2020:Some Text:275.81"
I need to get the value just before each comma and then get the lowest of these values. I know I can use min() if I get these values in a string. For the above example I need 275.81 (lowest).
Please see my code below. I am trying to explode the values and then put in a string. I dont think this is the best way by far and not having any luck. is there a better/cleaner way to do this?
$dates = explode(',', $resultx);
foreach($dates as $datew) {
$dater = explode(':', $datew);
echo $dater[2]. ",";
}
You can use regular expressions to extract the values, and then use min() to get the minimum value
<?php
$input = "2/6/2020:Some Text:345.44,13/6/2020:Some Text:375.88,14/6/2020:Some Text:275.81";
$pattern = '/(?:[^\:]+)\:(?:[^\:]+)\:(\d+\.\d+)\,*/';
if (preg_match_all($pattern, $input, $matches)) {
$minimumValue = min($matches[1]);
echo "minimum is: " . $minimumValue;
}
Here is a working example on 3v4l.org
In the pattern (?:[^\:]+) - equals any symbol, except the colon :
Section (\d+\.\d+) says that we need to capture the sequence containing two numbers with a dot . between them.
We look for two sections with any symbols, except :, and then capturing the third sections containing numbers, and everything ends with an optional comma ,
P.S. you could still get the result with your current approach
<?php
$input = "2/6/2020:Some Text:345.44,13/6/2020:Some Text:375.88,14/6/2020:Some Text:275.81";
$minimumValue = null;
$dates = explode(',', $input);
foreach($dates as $datew) {
$dater = explode(':', $datew);
$currentValue = floatval($dater[2]);
if (is_null($minimumValue) || $minimumValue > $currentValue) {
$minimumValue = $currentValue;
}
}
echo $minimumValue;
Here is a link to your approach on 3v4l.org

regular expression word preceded by char

I want to grab a specific string only if a certain word is followed by a = sign.
Also, I want to get all the info after that = sign until a / is reached or the string ends.
Let's take into example:
somestring.bla/test=123/ohboy/item/item=capture
I want to get item=capture but not item alone.
I was thinking about using lookaheads but I'm not sure it this is the way to go. I appreciate any help as I'm trying to grasp more and more about regular expressions.
[^/=]*=[^/]*
will give you all the pairs that match your requirements.
So from your example it should return:
test=123
item=capture
Refiddle Demo
If you want to capture item=capture, it is straightforward:
/item=[^\/]*/
If you want to also extract the value,
/item=([^\/]*)/
If you only want to match the value, then you need to use a look-behind.
/(?<=item=)[^\/]*/
EDIT: too many errors due to insomnia. Also, screw PHP and its failure to disregard separators in a character group as separators.
Here is a function I wrote some time ago. I modified it a little, and added the $keys argument so that you can specify valid keys:
function getKeyValue($string, Array $keys = null) {
$keys = (empty($keys) ? '[\w\d]+' : implode('|', $keys));
$pattern = "/(?<=\/|$)(?P<key>{$keys})\s*=\s*(?P<value>.+?)(?=\/|$)/";
preg_match_all($pattern, $string, $matches, PREG_SET_ORDER);
foreach ($matches as & $match) {
foreach ($match as $key => $value) {
if (is_int($key)) {
unset($match[$key]);
}
}
}
return $matches ?: FALSE;
}
Just trow in the string and valid keys:
$string = 'somestring.bla/test=123/ohboy/item/item=capture';
$keys = array('test', 'item');
$keyValuePairs = getKeyValue($string, $keys);
var_dump($keyValuePairs);

Get sentence(s) which include(s) searched word(s)?

I want to get sentence(s) which include(s) searched word(s). I have tried this but can't make it work properly.
$string = "I think instead of trying to find sentences, I'd think about the amount of
context around the search term I would need in words. Then go backwards some fraction of this number of words (or to the beginning) and forward the remaining number
of words to select the rest of the context.";
$searchlocation = "fraction";
$offset = stripos( strrev(substr($string, $searchlocation)), '. ');
$startloc = $searchlocation - $offset;
echo $startloc;
You can get all sentences.
try this:
$string = "I think instead of trying to find sentences, I'd think about the amount of
context around the search term I would need in words. Then go backwards some fraction of this number of words (or to the beginning) and forward the remaining number
of words to select the rest of the context.";
$searchlocation = "fraction";
$sentences = explode('.', $string);
$matched = array();
foreach($sentences as $sentence){
$offset = stripos($sentence, $searchlocation);
if($offset){ $matched[] = $sentence; }
}
var_export($matched);
using array_filter function
$sentences = explode('.', $string);
$result = array_filter(
$sentences,
create_function('$x', "return strpos(\$x, '$searchlocation');"));
Note: the double quote in the second parameter of create_function is necessary.
If you have anonymous function support, you can use this,
$result = array_filter($sentences, function($x) use($searchlocation){
return strpos($x, $searchlocation)!==false;
});
Since you reverse the string with strrev(), you will find [space]. instead of .[space].

PHP Tokens From a String

Let's say you have a string that looks like this:
token1 token2 tok3
And you want to get all of the tokens (specifically the strings between the spaces), AND ALSO their position (offset) and length).
So I would want a result that looks something like this:
array(
array(
'value'=>'token1'
'offset'=>0
'length'=>6
),
array(
'value'=>'token2'
'offset'=>7
'length'=>6
),
array(
'value'=>'tok3'
'offset'=>14
'length'=>4
),
)
I know that this can be done by simply looping through the characters of the string and I can simpy write a function to do this.
I am wondering, does PHP have anything built-in that will do this efficiently or at least help with part of this?
I am looking for suggestions and appreciate any help given. Thanks
You can use preg_match_all with the PREG_OFFSET_CAPTURE flag:
$str = 'token1 token2 tok3';
preg_match_all('/\S+/', $str, $matches, PREG_OFFSET_CAPTURE);
var_dump($matches);
Then you just need to replace the items in $matches[0] like this:
function update($match) {
return array( 'value' => $value[0], 'offset' => $value[1], 'length' => strlen($value[0]));
}
array_map('update', $matches[0]);
var_dump($matches[0]);
There's a simpler way, in most respects. You'll have a more basic result, but with much less work put in.
Assuming you have tokena tokenb tokenc stored in $data
$tokens = explode(' ', $data);
Now you have an array of tokens separated by spaces. They will be in order, so $tokens[0] = tokena, $tokens[1] = tokenb, etc. You can very easily get the length of any given item by doing strlen($tokens[$index]); If you need to know how many tokens you were passed, use $token_count = count($tokens);
Not as sophisticated, but next to no work to get it.
You could use explode(), which will give you an array of tokens from the string, and strlen() to count the number of characters in the string. As far as I know, I don't think there is a PHP function to tell you where an element is in an array.
To get around the last problem, you could use a counter variable that loops through the explod()ed array (foreach() for for()) and gives each sub-array in the new data it's position.
Someone please correct my if I'm wrong.
James
I like the first answer the most - to use PREG_OFFSET_CAPTURE. In case anyone else is interested, I ended up writing something that does this as well, although I am going to accept the first answer.
Thank you everybody for helping!
function get_words($string) {
$string_chars = str_split($string);
$words = array();
$curr_offset = 0;
foreach($reduced_string_chars as $offset=>$char) {
if ($char == ' ') {
if ($length) $words[] = array('offset'=>$curr_offset,'length'=>$length,'value'=>implode($value_array));
$curr_offset = $offset;
$length = 0;
$value_array = array();
}
else {
$length++;
$value_array[] = $char;
}
}
return $words;
}

Categories