php preg_match testing commas more than twice - php

I have this:
$subject ="bla foo bar, blafoo, blabla, ";
$pattern = '/, {2,}/';
if (preg_match($pattern, $subject)){
echo "true";
}else{
echo "false";
}
I want to test whether comma+space occurs twice or more often in the subject. However, the above returns false. So I'm doing something wrong.

Since you are looking for a literal substring, use substr_count:
if (substr_count($subject, ', ') > 2) {
...
} else {
...
}
If you want to do the same but this time with a regex, use preg_match_all that returns the number of occurrences in the same way.
To repeat several characters/tokens in the pattern itself, you need to group them. You can use a non-capturing group (?:...):
(?:, ){2,}
Without a group, only the last token is repeated. (so the space in your example).
But this pattern doesn't describe your string since there are other character between the commas, you must add them:
(?:, [^,]*){2,}

Let's ignore the fact that if you want to check exactly what you're posting, it'd be more efficient to compare strpos($subject, ', ') != strrpos($subject, ', ').
There are 2 problems with your regexp, the repetition is applied to the space only (not the sequence) plus you leave no room for any other characters, so your regexp currently checks if your subject contains ,<SP><SP>
Fixing both issues would lead to:
var_dump(preg_match('~(, .*){2,}~', $subject));

Related

Find and replace string with condition in php

I am newbie in PHP. I want to replace certain characters in a string. My code is in below:
$str="this 'is' a new 'string and i wanna' replace \"in\" \"it here\"";
$find = [
'\'',
'"'
];
$replace = [
['^', '*']
['#', '#']
];
$result = null;
$odd = true;
for ($i=0; $i < strlen($str); $i++) {
if (in_array($str[$i], $find)) {
$key = array_search($str[$i], $find);
$result .= $odd ? $replace[$key][0] : $replace[$key][1];
$odd = !$odd;
} else {
$result .= $str[$i];
}
}
echo $result;
the output of the above code is:
this ^is* a new ^string and i wanna* replace #in# #it here#.
but I want the output to be:
this ^is* a new 'string and i wanna' replace #in# "it here".
That means character will replace for both quotation(left quotation and right quotation- condition is for ' and "). for single quotation, string will not be replaced either if have left or right quotation. it will be replaced for left and right quotation.
Ok, I don't know what all that code is trying to accomplish.
But anyway here is my go at it
$str = "this 'is' a new 'string and i wanna' replace \"in\" \"it here\"";
$str = preg_replace(["/'([^']+)'/",'/"([^"]+)"/'], ["^$1*", "#$1#"], $str, 1);
print_r($str);
You can test it here
Ouptput
this ^is* a new 'string and i wanna' replace #in# "it here"
Using preg_replace and a fairly simple Regular expression, we can replace the quotes. Now the trick here is the fourth parameter of preg_replace is $count And is defined as this:
count If specified, this variable will be filled with the number of replacements done.
Therefore, setting this to 1 limits it to the first match only. In other words it will do $count replacements, or 1 in this case. Now because it's an array of patterns, each pattern is treated separately. So each one is basically treated as a separate operation, and thus each is allowed $count matches, or each get 1 match/replacement.
Now rather or not this fits every use case you have I cannot say, but it's the most straight forward way to do it for the example you provided.
As for the match itself /'([^']+)'/
/ opening and closing "delimiters" for the Expression (its a required thing, although it doesn't have to be /)
' literal match, matches ' one time (the opening quote)
( ... ) capture group (group1) so we can use it in the replacement, as $1
[^']+ character set with a [^ not modifier, match anything not in the set, so anything that is not a ' one or more times, greedy
' literal match, matches ' one time (the ending quote)
The replacement "^$1*"
^ literal, adds this char in
$1 use the contents of the capture group (group1)
* literal, adds the char in
Hope that helps understand how it works.
UPDATE
Ok I think I finally deciphered what you want:
string will be replaced for if any word have left and right quotation. example..'word'..here string will be changed..but 'word...in this case not change or word' also not be changed.
This seems like you are trying to say only "whole" words with no spaces.
So in that case we have to adjust our regular expression like this:
$str = preg_replace(["/'([-\w]+)'/",'/"([-\w]+)"/'], ["^$1*", "#$1#"], $str);
So we removed the limit $count and we changed what is in the character group to be more strict:
[-\w]+ the \w means the working set, or in other words a-zA-Z0-9_ then the - is a literal (it has to/should go first in this case)
What we are saying with this is to match only strings that start and end with a quote(single|double) and only if the string within them match the working set plus the hyphen. This does not include the space. This way in the first case, your example, it produces the same result, but if you were to flip it to
//[ORIGINAL] this 'is' a new 'string and i wanna' replace \"in\" \"it here\"
this a new 'string and i wanna' replace 'is' \"it here\" \"in\"
You would get his output
this a new 'string and i wanna' replace ^is* \"it here\" #in#
Before this change you would have gotten
this a new ^string and i wanna* replace 'is' #it here# "in"
In other words it would have only replaced the first occurrence, now it will replace anything between the quotes if and only if it's a whole word.
As a final note you can be even more strict if you only want alpha characters by changing the character set to this [a-zA-Z]+, then it will match only a to z, upper or lower case. Whereas the example above will match 0 to 9 (or any combination of them) the - hyphen, the _ underline and the previously mentioned alpha sets.
Hope that is what you need.

Make two simple regex's into one

I am trying to make a regex that will look behind .txt and then behind the "-" and get the first digit .... in the example, it would be a 1.
$record_pattern = '/.txt.+/';
preg_match($record_pattern, $decklist, $record);
print_r($record);
.txt?n=chihoi%20%283-1%29
I want to write this as one expression but can only seem to do it as two. This is the first time working with regex's.
You can use this:
$record_pattern = '/\.txt.+-(\d)/';
Now, the first group contains what you want.
Your regex would be,
\.txt[^-]*-\K\d
You don't need for any groups. It just matches from the .txt and upto the literal -. Because of \K in our regex, it discards the previously matched characters. In our case it discards .txt?n=chihoi%20%283- string. Then it starts matching again the first digit which was just after to -
DEMO
Your PHP code would be,
<?php
$mystring = ".txt?n=chihoi%20%283-1%29";
$regex = '~\.txt[^-]*-\K\d~';
if (preg_match($regex, $mystring, $m)) {
$yourmatch = $m[0];
echo $yourmatch;
}
?> //=> 1

php expressions preg_match

I have been trying to figure this out really hard and I cannot came out with a solution ,
I have an arrary of strings which is
"Descripcion 1","Description 2"
and I need to filter by numbers, so I thought maybe I can use preg_match() and find when there is exactly 1 number 1 or two or etc, and do my logic, becouse the string before the number may change, but the number cannot, I have tried using
preg_match(" 1{1}","Description 1")
which is suppossed to return true when finds an space followed by the string "1" exactly one time but returns false.
Maybe some of you have had more experience with regular expressions in php and can help me.
Thank you very much in advance.
You could use strpos instead of preg_match!
foreach($array as $string) {
if(strpos($string, ' 1') !== false) {
//String contains " 1"!!
}
}
This would be much faster then a regular expression.
Or, if the Number has to be at the end of the string:
foreach($array as $string) {
if(substr($string, -2) == ' 1') {
//String ends with " 1"!!
}
}
You forgot the regex delimiters. Use preg_match('/ 1/', ...) instead.
However, you do not need a regex at all if you just want to test if a string is contained within another string! See Lars Ebert's answer.
You might have success using
if (preg_match('/(.*\s[1])/', $var, $array)) {
$descrip = $array[1];
} else {
$descrip = "";
}
I tested the above regex on the 3 separate string values of descripcion 1, thisIsAnother 1, andOneMore 1. Each were found to be true by the expression and were saved into group 1.
The explanation of the regex code is:
() Match the regular expression between the parentheses and capture the match into backreference number 1.
.* Match any single character that is not a line break character between zero and as many times possible (greedy)
\s Match a single whitespace character (space, tab, line break)
[1] Match the character 1

Identifying a random repeating pattern in a structured text string

I have a string that has the following structure:
ABC_ABC_PQR_XYZ
Where PQR has the structure:
ABC+JKL
and
ABC itself is a string that can contain alphanumeric characters and a few other characters like "_", "-", "+", "." and follows no set structure:
eg.qWe_rtY-asdf or pkl123
so, in effect, the string can look like this:
qWe_rtY-asdf_qWe_rtY-asdf_qWe_rtY-asdf+JKL_XYZ
My goal is to find out what string constitutes ABC.
I was initially just using
$arrString = explode("_",$string);
to return $arrString[0] before I was made aware that ABC ($arrString[0]) itself can contain underscores, thus rendering it incorrect.
My next attempt was exlpoding it on "_" anyway and then comparing each of the exploded string parts with the first string part until I get a semblance of a pattern:
function getPatternABC($string)
{
$count = 0;
$pattern ="";
$arrString = explode("_", $string);
foreach($arrString as $expString)
{
if(strcmp($expString,$arrString[0])!==0 || $count==0)
{
$pattern = $pattern ."_". $arrString[$count];
$count++;
}
else break;
}
return substr($pattern,1);
}
This works great - but I wanted to know if there was a more elegant way of doing this using regular expressions?
Here is the regex solution:
'^([a-zA-Z0-9_+-]+)_\1_\1\+'
What this does is match (starting from the beginning of the string) the longest possible sequence consisting of the characters inside the square brackets (edit that per your spec). The sequence must appear exactly twice, each time followed by an underscore, and then must appear once more followed by a plus sign (this is actually the first half of PQR with the delimiter before JKL). The rest of the input is ignored.
You will find ABC captured as capture group 1.
So:
$input = 'qWe_rtY-asdf_qWe_rtY-asdf_qWe_rtY-asdf+JKL_XYZ';
$result = preg_match('/^([a-zA-Z0-9_+-]+)_\1_\1\+/', $input, $matches);
if ($result) {
echo $matches[2];
}
See it in action.
Sure, just make a regular expression that matches your pattern. In this case, something like this:
preg_match('/^([a-zA-Z0-9_+.-]+)_\1_\1\+JKL_XYZ$/', $string, $match);
Your ABC is in $match[1].
If the presence of underscores in these strings has a low frequency, it may be worth checking to see if a simple explode() will do it before bothering with regex.
<?php
$str = 'ABC_ABC_PQR_XYZ';
if(substr_count($str, '_') == 3)
$abc = reset(explode('_', $str));
else
$abc = regexy_function($str);
?>

How do I tell regex to match at least x number of alphanumeric?

I have form where user submits field. Field can have letters, numbers, and punctuation. But I want to check to make sure that at least 3 of the characters are letters. How can I regex that?
For example,
$string = "ab'c";
And I need something like,
if (preg_match("/[a-z]{3}/i", $string))
print "true";
else
print "false";
That string has three letters, even though it has an apostrophe. It should test true. But for some reason, that tests false right now.
Any help?
How about a case insensitive match on:
([a-z][^a-z]*){3}
Looks for 3 groups of a letter, and any number of non letters.
You cannot write a regexp that checks for "at least x symbols of a class". Of course you can
preg_match_all('~([a-z][^a-z]*){3}~', "ab'c")
In more complex cases, you can replace the class to something else and then compare results (or simply use preg_replace fourth parameter):
preg_replace('~[a-z]~', '', "ab'c", -1, $count);
print_r($count); // prints "3"
Try this regular expression:
^([0-9,]*[A-Za-z]){3}[A-Za-z0-9,]*$
You could also remove all non-letter characters and check the length:
if (strlen(preg_replace('/[^A-Za-z]+/', '', $str)) >= 3) {
// $str contains at least three letters
}
Try this:
The $ matches the end of the string ;)
if (preg_match("/[a-zA-Z\']{3}$/i", $string))
print "true";
else
print "false";
Edit:
Sorry, I misunderstood your question. Try this:
^([a-zA-Z\']{3,}(.?))$
Results:
hell'o <-- true
h31l0 <-- false
hello <-- true

Categories