Why is my preg_match_all not working? - php

I am using preg_match_all to ensure that a string follows a certain pattern.
It should display 'all conditions are met' becuase the string follows the pattern, but instead, it displays 'conditions net met'.
$order = "item[]=2&item[]=1&item[]=3&item[]=4&item[]=5&item[]=6&item[]=7&item[]=8&item[]=9&item[]=10&item[]=11&item[]=12";
$pattern = "/^(item\[\]=([1-9]|10|11|12))(&(item\[\]=([1-9]|10|11|12))){11}$/";
if(preg_match($pattern, $order)) {
// check for repetition
$matches = [];
preg_match_all("/\d+/", $order, $matches);
if(count(array_count_values($matches[0])) == 12) {
// All are unique values
echo 'All conditions met';
}
}else{
echo 'Conditions not met';
}

The right way would be using parse_str(to parse quesry string: key/value pairs separated with &) and array_diff(to check if all numbers from the needed range 1-12 are present and not repeated) functions:
$order = "item[]=2&item[]=1&item[]=3&item[]=4&item[]=5&item[]=6&item[]=7&item[]=8&item[]=9&item[]=10&item[]=11&item[]=12";
parse_str($order, $items);
if (isset($items['item']) && is_array($items['item'])
&& count($items['item']) == 12 && !array_diff(range(1, 12), $items['item'])) {
echo 'All conditions met';
} else {
echo 'Conditions not met';
}

Try this:
<?php
$order = "item[]=2&item[]=1&item[]=3&item[]=4&item[]=5&item[]=6&item[]=7&item[]=8&item[]=9&item[]=10&item[]=11&item[]=12";
$pattern = "/^(item\[\]=([1-9]|10|11|12))(&(item\[\]=([1-9]|10|11|12))){11}$/";
if(preg_match($pattern, $order)) {
// check for repetition
$matches = [];
preg_match_all("/\d+/", $order, $matches);
if(count(array_count_values($matches[0])) == $movienumber) {
// All are unique values
echo 'All conditions met';
}
}else{
echo 'Conditions not met';
}
You were missing a ) in pattern.

Assuming the input string is valid (all conditions are met) when it contains in item[] all the values from 1 to 12, this simple piece of code works faster than preg_match() and it's easier to understand:
// Input string
$order = "item[]=2&item[]=1&item[]=3&item[]=4&item[]=5&item[]=6&item[]=7&item[]=8&item[]=9&item[]=10&item[]=11&item[]=12";
// Parse it to values and store them in $pieces
$pieces = array();
parse_str($order, $pieces);
// Need to sort the values to let the comparison succeed
sort($pieces['item']);
$valid = ($pieces['item'] == range(1, 12));
// Verification
var_dump($valid);
// It prints:
// bool(true)

Related

How can I see if a string matches a PHP array of regex values?

I am using my URI's to determine if the page footer should be included or not. I have an array of regex patterns and I want to see if the current uri matches any of the regex patterns in my array. How can I do this?
$blocked = array(
'blog/comments/add([0-9]+)'
);
if(/* uri does not match any regex pattern in the above array */){
$this->load->view('overall_footer');
}
You have to loop through the entire array and check each and every one of the array elements with preg_match
<?php
$blocked = array(
'blog/comments/add([0-9]+)'
);
foreach ($blocked as $current) {
$result = null;
$match = preg_match("#" . $current . "#", $_SERVER["REQUEST_URI"], $result);
if($match == 1) {
echo "found<br />";
print_r($result);
break;
}
}
?>

Check if string contains a value in array [duplicate]

This question already has answers here:
String contains any items in an array (case insensitive)
(15 answers)
Closed 2 years ago.
I am trying to detect whether a string contains at least one URL that is stored in an array.
Here is my array:
$owned_urls = array('website1.com', 'website2.com', 'website3.com');
The string is entered by the user and submitted via PHP. On the confirmation page I would like to check if the URL entered is in the array.
I have tried the following:
$string = 'my domain name is website3.com';
if (in_array($string, $owned_urls))
{
echo "Match found";
return true;
}
else
{
echo "Match not found";
return false;
}
No matter what is inputted the return is always "Match not found".
Is this the correct way of doing things?
Try this.
$string = 'my domain name is website3.com';
foreach ($owned_urls as $url) {
//if (strstr($string, $url)) { // mine version
if (strpos($string, $url) !== FALSE) { // Yoshi version
echo "Match found";
return true;
}
}
echo "Not found!";
return false;
Use stristr() or stripos() if you want to check case-insensitive.
This was a lot easier to do if all you want to do is find a string in an array.
$array = ["they has mystring in it", "some", "other", "elements"];
if (stripos(json_encode($array),'mystring') !== false) {
echo "found mystring";
}
Try this:
$owned_urls= array('website1.com', 'website2.com', 'website3.com');
$string = 'my domain name is website3.com';
$url_string = end(explode(' ', $string));
if (in_array($url_string,$owned_urls)){
echo "Match found";
return true;
} else {
echo "Match not found";
return false;
}
-
Thanks
Simple str_replace with count parameter would work here:
$count = 0;
str_replace($owned_urls, '', $string, $count);
// if replace is successful means the array value is present(Match Found).
if ($count > 0) {
echo "One of Array value is present in the string.";
}
More Info - https://www.techpurohit.in/extended-behaviour-explode-and-strreplace-php
I think that a faster way is to use preg_match.
$user_input = 'Something website2.com or other';
$owned_urls_array = array('website1.com', 'website2.com', 'website3.com');
if ( preg_match('('.implode('|',$owned_urls_array).')', $user_input)){
echo "Match found";
}else{
echo "Match not found";
}
$string = 'my domain name is website3.com';
$a = array('website1.com','website2.com','website3.com');
$result = count(array_filter($a, create_function('$e','return strstr("'.$string.'", $e);')))>0;
var_dump($result );
output
bool(true)
Here is a mini-function that search all values from an array in a given string.
I use this in my site to check for visitor IP is in my permitted list on certain pages.
function array_in_string($str, array $arr) {
foreach($arr as $arr_value) { //start looping the array
if (stripos($str,$arr_value) !== false) return true; //if $arr_value is found in $str return true
}
return false; //else return false
}
how to use
$owned_urls = array('website1.com', 'website2.com', 'website3.com');
//this example should return FOUND
$string = 'my domain name is website3.com';
if (array_in_string($string, $owned_urls)) {
echo "first: Match found<br>";
}
else {
echo "first: Match not found<br>";
}
//this example should return NOT FOUND
$string = 'my domain name is website4.com';
if (array_in_string($string, $owned_urls)) {
echo "second: Match found<br>";
}
else {
echo "second: Match not found<br>";
}
DEMO: http://phpfiddle.org/lite/code/qf7j-8m09
stripos function is not very strict. it's not case sensitive or it can match a part of a word
http://php.net/manual/ro/function.stripos.php
if you want that search to be case sensitive use strpos
http://php.net/manual/ro/function.strpos.php
for exact match use regex (preg_match), check this guy answer https://stackoverflow.com/a/25633879/4481831
You can concatenate the array values with implode and a separator of |
and then use preg_match to search for the value.
Here is the solution I came up with ...
$emails = array('#gmail', '#hotmail', '#outlook', '#live', '#msn', '#yahoo', '#ymail', '#aol');
$emails = implode('|', $emails);
if(!preg_match("/$emails/i", $email)){
// do something
}
If your $string is always consistent (ie. the domain name is always at the end of the string), you can use explode() with end(), and then use in_array() to check for a match (as pointed out by #Anand Solanki in their answer).
If not, you'd be better off using a regular expression to extract the domain from the string, and then use in_array() to check for a match.
$string = 'There is a url mysite3.com in this string';
preg_match('/(?:http:\/\/)?(?:www.)?([a-z0-9-_]+\.[a-z0-9.]{2,5})/i', $string, $matches);
if (empty($matches[1])) {
// no domain name was found in $string
} else {
if (in_array($matches[1], $owned_urls)) {
// exact match found
} else {
// exact match not found
}
}
The expression above could probably be improved (I'm not particularly knowledgeable in this area)
Here's a demo
You are checking whole string to the array values. So output is always false.
I use both array_filter and strpos in this case.
<?php
$urls= array('website1.com', 'website2.com', 'website3.com');
$string = 'my domain name is website3.com';
$check = array_filter($urls, function($url){
global $string;
if(strpos($string, $url))
return true;
});
echo $check?"found":"not found";
$owned_urls= array('website1.com', 'website2.com', 'website3.com');
$string = 'my domain name is website3.com';
for($i=0; $i < count($owned_urls); $i++)
{
if(strpos($string,$owned_urls[$i]) != false)
echo 'Found';
}
$message = "This is test message that contain filter world test3";
$filterWords = array('test1', 'test2', 'test3');
$messageAfterFilter = str_replace($filterWords, '',$message);
if( strlen($messageAfterFilter) != strlen($message) )
echo 'message is filtered';
else
echo 'not filtered';
I find this fast and simple without running loop.
$array = array("this", "that", "there", "here", "where");
$string = "Here comes my string";
$string2 = "I like to Move it! Move it";
$newStr = str_replace($array, "", $string);
if(strcmp($string, $newStr) == 0) {
echo 'No Word Exists - Nothing got replaced in $newStr';
} else {
echo 'Word Exists - Some Word from array got replaced!';
}
$newStr = str_replace($array, "", $string2);
if(strcmp($string2, $newStr) == 0) {
echo 'No Word Exists - Nothing got replaced in $newStr';
} else {
echo 'Word Exists - Some Word from array got replaced!';
}
Little explanation!
Create new variable with $newStr replacing value in array of original string.
Do string comparison - If value is 0, that means, strings are equal and nothing was replaced, hence no value in array exists in string.
if it is vice versa of 2, i.e, while doing string comparison, both original and new string was not matched, that means, something got replaced, hence value in array exists in string.
$search = "web"
$owned_urls = array('website1.com', 'website2.com', 'website3.com');
foreach ($owned_urls as $key => $value) {
if (stristr($value, $search) == '') {
//not fount
}else{
//found
}
this is the best approach search for any substring , case-insensitive and fast
just like like im mysql
ex:
select * from table where name = "%web%"
I came up with this function which works for me, hope this will help somebody
$word_list = 'word1, word2, word3, word4';
$str = 'This string contains word1 in it';
function checkStringAgainstList($str, $word_list)
{
$word_list = explode(', ', $word_list);
$str = explode(' ', $str);
foreach ($str as $word):
if (in_array(strtolower($word), $word_list)) {
return TRUE;
}
endforeach;
return false;
}
Also, note that answers with strpos() will return true if the matching word is a part of other word. For example if word list contains 'st' and if your string contains 'street', strpos() will return true

Find and replace duplicates in Array

I need to make app with will fill array with some random values, but if in array are duplicates my app not working correctly. So I need to write script code which will find duplicates and replace them with some other values.
Okay so for example i have an array:
<?PHP
$charset=array(123,78111,0000,123,900,134,00000,900);
function arrayDupFindAndReplace($array){
// if in array are duplicated values then -> Replace duplicates with some other numbers which ones I'm able to specify.
return $ArrayWithReplacedValues;
}
?>
So result shall be the same array with replaced duplicated values.
You can just keep track of the words that you've seen so far and replace as you go.
// words we've seen so far
$words_so_far = array();
// for each word, check if we've encountered it so far
// - if not, add it to our list
// - if yes, replace it
foreach($charset as $k => $word){
if(in_array($word, $words_so_far)){
$charset[$k] = $your_replacement_here;
}
else {
$words_so_far[] = $word;
}
}
For a somewhat-optimized solution (for cases where there are not that many duplicates), use array_count_values() (reference here) to count the number of times it shows up.
// counts the number of words
$word_count = array_count_values($charset);
// words we've seen so far
$words_so_far = array();
// for each word, check if we've encountered it so far
// - if not, add it to our list
// - if yes, replace it
foreach($charset as $k => $word){
if($word_count[$word] > 1 && in_array($word, $words_so_far)){
$charset[$k] = $your_replacement_here;
}
elseif($word_count[$word] > 1){
$words_so_far[] = $word;
}
}
Here the example how to generate unique values and replace recurring values in array
function get_unique_val($val, $arr) {
if ( in_array($val, $arr) ) {
$d = 2; // initial prefix
preg_match("~_([\d])$~", $val, $matches); // check if value has prefix
$d = $matches ? (int)$matches[1]+1 : $d; // increment prefix if exists
preg_match("~(.*)_[\d]$~", $val, $matches);
$newval = (in_array($val, $arr)) ? get_unique_val($matches ? $matches[1].'_'.$d : $val.'_'.$d, $arr) : $val;
return $newval;
} else {
return $val;
}
}
function unique_arr($arr) {
$_arr = array();
foreach ( $arr as $k => $v ) {
$arr[$k] = get_unique_val($v, $_arr);
$_arr[$k] = $arr[$k];
}
unset($_arr);
return $arr;
}
$ini_arr = array('dd', 'ss', 'ff', 'nn', 'dd', 'ff', 'vv', 'dd');
$res_arr = unique_arr($ini_arr); //array('dd', 'ss', 'ff', 'nn', 'dd_2', 'ff_2', 'vv', 'dd_3');
Full example you can see here webbystep.ru
Use the function
array_unique()
See more info at http://php.net/manual/en/function.array-unique.php
$uniques = array();
foreach ($charset as $value)
$uniques[$value] = true;
$charset = array_flip($uniques);

wildcard array comparison - improving efficiency

I have two arrays that I'm comparing and I'd like to know if there is a more efficient way to do it.
The first array is user submitted values, the second array is allowed values some of which may contain a wildcard in the place of numbers e.g.
// user submitted values
$values = array('fruit' => array(
'apple8756apple333',
'banana234banana',
'apple4apple333',
'kiwi435kiwi'
));
//allowed values
$match = array('allowed' => array(
'apple*apple333',
'banana234banana',
'kiwi*kiwi'
));
I need to know whether or not all of the values in the first array, match a value in the second array.
This is what I'm using:
// the number of values to validate
$valueCount = count($values['fruit']);
// the number of allowed to compare against
$matchCount = count($match['allowed']);
// the number of values passed validation
$passed = 0;
// update allowed wildcards to regular expression for preg_match
foreach($match['allowed'] as &$allowed)
{
$allowed = str_replace(array('*'), array('([0-9]+)'), $allowed);
}
// for each value match against allowed values
foreach($values['fruit'] as $fruit)
{
$i = 0;
$status = false;
while($i < $matchCount && $status == false)
{
$result = preg_match('/' . $match['allowed'][$i] . '/', $fruit);
if ($result)
{
$status = true;
$passed++;
}
$i++;
}
}
// check all passed validation
if($passed === $valueCount)
{
echo 'hurray!';
}
else
{
echo 'fail';
}
I feel like I might be missing out on a PHP function that would do a better job than a while loop within a foreach loop. Or am I wrong?
Update: Sorry I forgot to mention, numbers may occur more than 1 place within the values, but there will only ever be 1 wildcard. I've updated the arrays to represent this.
If you don't want to have a loop inside another, it would be better if you grouped your $match regex.
You could get the whole functionality with a lot less code, which might arguably be more efficient than your current solution:
// user submitted values
$values = array(
'fruit' => array(
'apple8756apple',
'banana234banana',
'apple4apple',
'kiwi51kiwi'
)
);
$match = array(
'allowed' => array(
'apple*apple',
'banana234banana',
'kiwi*kiwi'
)
);
$allowed = '('.implode(')|(',$match['allowed']).')';
$allowed = str_replace(array('*'), array('[0-9]+'), $allowed);
foreach($values['fruit'] as $fruit){
if(preg_match('#'.$allowed.'#',$fruit))
$matched[] = $fruit;
}
print_r($matched);
See here: http://codepad.viper-7.com/8fpThQ
Try replacing /\d+/ in the first array with '*', then do array_diff() between the 2 arrays
Edit: after clarification, here's a more refined approach:
<?php
$allowed = str_replace("*", "\d+", $match['allowed']);
$passed = 0;
foreach ($values['fruit'] as $fruit) {
$count = 0;
preg_replace($allowed, "", $fruit, -1, $count); //preg_replace accepts an array as 1st argument and stores the replaces done on $count;
if ($count) $passed++;
}
if ($passed == sizeof($values['fruit']) {
echo 'hurray!';
} else {
echo 'fail';
}
?>
The solution above does not remove the need for a nested loop, but it merely lets PHP do the inner loop, which may be faster (you should actually benchmark it)

Form a new string with data from an array PHP

I would need to reduce the quantity of these numbers and present them in a more concise way, instead of presenting several lines of numbers with the same "prefix" or "root". For example:
If I have an array like this, with several strings of numbers (obs: only numbers and the array is already sorted):
$array = array(
"12345647",
"12345648",
"12345649",
"12345657",
"12345658",
"12345659",
);
The string: 123456 is the same in all elements of the array, so it would be the root or the prefix of the number. According to the above array I would get a result like this:
//The numbers in brackets represent the sequence of the following numbers,
//instead of showing the rows, I present all the above numbers in just one row:
$stringFormed = "123456[4-5][7-9]";
Another example:
$array2 = array(
"1234",
"1235",
"1236",
"1247",
"2310",
"2311",
);
From the second array, I should get a result like this:
$stringFormed1 = "123[4-7]";
$stringFormed2 = "1247";
$stringFormed3 = "231[0-1]";
Any idea?
$array = array(
"12345647",
"12345648",
"12345649",
"12345657",
"12345658",
"12345659",
);
//find common string positions for all elements
$res = array();
foreach($array as $arr){
for($i=0;$i<strlen($arr);$i++){
$res[$i][$arr[$i]] = $arr[$i];
}
}
//make final string
foreach($res as $pos){
if(count($pos)==1)
$str .= implode('',$pos);
else{
//u may need to sort these values if you want them in order
$end = end($pos);
$first = reset($pos);
$str .="[$first-$end]";
}
}
echo $str; // "123456[4-5][7-9]";
Well, as I understand you want the final string with unique characters. (i'm not sure if you want it ordered)
So, first implode to create the string
$stringFormed = implode("", $array);
Then we get the unique chars :
$stringFormed=implode("",array_unique(str_split($stringFormed)));
OUTPUT: 123456789
That as a solution for first example but i didn't thought there could be several roots.
By the way i'm not sure it's well coded...
<?php
function longest_common_substring($words)
{
$words = array_map('strtolower', array_map('trim', $words));
$sort_by_strlen = create_function('$a, $b', 'if (strlen($a) == strlen($b)) { return strcmp($a, $b); } return (strlen($a) < strlen($b)) ? -1 : 1;');
usort($words, $sort_by_strlen);
// We have to assume that each string has something in common with the first
// string (post sort), we just need to figure out what the longest common
// string is. If any string DOES NOT have something in common with the first
// string, return false.
$longest_common_substring = array();
$shortest_string = str_split(array_shift($words));
while (sizeof($shortest_string)) {
array_unshift($longest_common_substring, '');
foreach ($shortest_string as $ci => $char) {
foreach ($words as $wi => $word) {
if (!strstr($word, $longest_common_substring[0] . $char)) {
// No match
break 2;
} // if
} // foreach
// we found the current char in each word, so add it to the first longest_common_substring element,
// then start checking again using the next char as well
$longest_common_substring[0].= $char;
} // foreach
// We've finished looping through the entire shortest_string.
// Remove the first char and start all over. Do this until there are no more
// chars to search on.
array_shift($shortest_string);
}
// If we made it here then we've run through everything
usort($longest_common_substring, $sort_by_strlen);
return array_pop($longest_common_substring);
}
$array = array(
"12345647",
"12345648",
"12345649",
"12345657",
"12345658",
"12345659",
);
$result= longest_common_substring($array);
for ($i = strlen($result); $i < strlen($array[0]); $i++) {
$min=intval($array[0][$i]);
$max=$min;
foreach ($array as $string) {
$val = intval($string[$i]);
if($val<$min)
$min=$val;
elseif($val>$max)
$max=$val;
}
$result.='['.$min.'-'.$max.']';
}
echo $result;
?>

Categories