I'm attempting to utilize the following Regex pattern:
$regex = '/Name: [a-zA-Z ]*] [0-9]/';
When testing it in Rubular, it works fine, but when using PHP the expression never returns true, even when it should. Incidentally, if I remove the "[0-9]" part, it works fine. Is there some difference in PHP's regex syntax that I'm overlooking?
Edit:
I'm looking for the characters "Name:" then a name containing any number of letters or spaces, then a "]", then a space, then a single number. So
"Name: Chris] 5" would return true and
"Name: Chris] [lorem ipsum]" should return false.
I also tried escaping the second bracket "\[" but this did not fix the problem.
It's not clear without examples what your use case, but it seems like you want something like this?
$regex = '/Name\:\ ([\w]+)\ ([\w]+)/';
Update: try this:
$regex = '/Name\:\ [\w\s]+?\]\ [\d]{1}/';
For me this matches
Name: Foo Bar] 2
..but not these:
Name: Foo Bar] foo
Name: Foo Baz 5
I'm also using short-hand expressions for character classes:
[\w] is short for [a-zA-Z0-9] ( eg all alphanumeric characters )
[\s] matches any whitespace
[\d] matches any number
For safety I'm also using the '?' to match in a non-greedy way, to make sure thw [\w\s]+ match doesn't consume too much of the string.
i think this might be because of the space in the regex also u want to escape the second ]. try
$regex = '/Name:\s[a-zA-Z ]*\]\s[0-9]/';
Or use a modifier
$regex = '/Name: [a-zA-Z ]*\] [0-9]/x';
more on modifiers here
PHP: Possible modifiers in regex patterns - Manual
Your regex works nicely for me with the two examples you gave.
$arr = array('Name: Chris] 5', 'Name: Chris] [lorem ipsum]');
foreach ($arr as $str) {
if (preg_match('/Name: [a-zA-Z ]*] [0-9]/', $str)) {
echo "$str : OK\n";
} else {
echo "$str : KO\n";
}
}
Output:
Name: Chris] 5 : OK
Name: Chris] [lorem ipsum] : KO
May be there are more than one space between ] and the digit, so your regex should be:
[a-zA-Z ]*]\s+[0-9]/
I ended up resolving the issue by attempting different regexes that did basically the same thing. This is what ended up working:
$regex = '/Name: [\w ]*][^[]{2}/';
Evidently the brackets weren't the problem, but there was something in my original code that wasn't working properly. Thank you everyone for all the help.
Related
This is the code:
<?php
$pattern =' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$text = "kdaiuyq7e611422^^$^vbnvcn^vznbsjhf";
$text_split = str_split($text,1);
$data = '';
foreach($text_split as $value){
if (preg_match("/".$value."/", $pattern )){
$data = $data.$value;
}
if (!preg_match('/'.$value.'/', $pattern )){
break;
}
}
echo $data;
?>
Current output:
kdaiuyq7e611422^^$^vbnvcn^vznbsjhf
Expected output:
kdaiuyq7e611422
Please help me editing my code error. In pattern there is no ^ or $. But preg_match is showing matched which is doubtful.
You string $text have ^ which will match the begin of the string $pattern.
So the preg_match('/^/', $pattern) will return true, then the ^ will append to $data.
You should escape the ^ as a raw char, not a special char with preg_match('/\^/', $pattern) by the help of preg_quote() which will escape the special char.
There is no need to split your string up like that, the whole point of a regular expression is you can specify all the conditions within the expression. You can condense your entire code down to this:
$pattern = '/^[[:word:] ]+/';
$text = 'kdaiuyq7e611422^^$^vbnvcn^vznbsjhf';
preg_match($pattern, $text, $matches);
echo $matches[0];
Kris has accurately isolated that escaping in your method is the monkey wrench. This can be solved with preg_quote() or wrapping pattern characters in \Q ... \E (force characters to be interpreted literally).
Slapping that bandaid on your method (as you have done while answering your own question) doesn't help you to see what you should be doing.
I recommend that you do away with the character mask, the str_split(), and the looped calls of preg_match(). Your task can be accomplished far more briefly/efficiently/directly with a single preg_match() call. Here is the clean way that obeys your character mask fully:
Code: (Demo)
$text = "kdaiuyq7e611422^^$^vbnvcn^vznbsjhf";
echo preg_match('/^[a-z\d ]+/i',$text,$out)?$out[0]:'No Match';
Output:
kdaiuyq7e611422
miknik's method was close to this, but it did not maintain 100% accuracy given your question requirements. I'll explain:
[:word:] is a POSIX Character Class (functioning like \w) that represents letters(uppercase and lowercase), numbers, and an underscore. Unfortunately for miknik, the underscore is not in your list of wanted characters, so this renders the pattern slightly inaccurate and may be untrustworthy for your project.
for an url routing I have
Patern :
/^\/stuff\/other-stuff\/(?:([^\/]\+?))$/i
Subject :
/stuff/other-stuff/foo-AB123456.html
why $num_matches is equal to 0 ??
$num_matches = preg_match_all($patern, $subject, $matches);
Help should be greatly appreciated :)
because of this:
[^\/]\+?
firstly there is no slash after other-stuff so you cannot find the sentence with a negated / secondly the + must not be escaped if you are doing this kind of match . + must only be escaped when you are doing a literal match.
the corrected regex should be :
^\/stuff\/other-stuff\/(?:(.+?))$
demo here : http://regex101.com/r/aV9cR0
will match foo-AB123456.html in the first capture
$patern= "#^/stuff/other-stuff/([^/]+)$#i";
$subject = "/stuff/other-stuff/foo-AB123456.html";
preg_match_all($patern, $subject, $matches);
print_r($matches[1]);
It looks to me like your regex could be simplified to something like:
(?i)^/stuff/other-stuff/[\w-.]+$
It would work like this:
<?php
$regex="~(?i)^/stuff/other-stuff/([\w-./]+)$~";
$string = "/stuff/other-stuff/foo-AB123456.html";
$hit = preg_match($regex,$string,$m);
echo $m[0]."<br />";
echo $m[1]."<br />";
?>
Output:
/stuff/other-stuff/foo-AB123456.html
foo-AB123456.html
Note that this could be done in a number of different ways.
Here are some details about the regex.
The ~ delimiter is nicer than the original / because you don't have to escape the slashes.
The parentheses in ([\w-.]+) capture the end of the url into Group 1. This is why $m[1] yields foo-AB123456.html
After the final slash, [\w-./]+ matches any number of letters or digits, underscores, dashes, dots and forward slashes. This is a "mini-spec" for what characters we expect there. If you want to allow anything at all, you could go with a simple dot.
Well im trying to replace the first number in a string in PHP, but not behaves as spected.
$str = 'A12:B17';
$newvalue = '987';
echo preg_replace('/(^[A-Za-z])\d+(.*)/', '\1'.$newvalue.'\2', $str);
The problem is \1 is well replaced when i put it alone, but when i put $newvalue and \2 the first \1 is ignored
input1:
echo preg_replace('/(^[A-Za-z])\d+(.*)/', '\1'.$newvalue.'\2', $str);
output1:
87:B17 // dissapears first character :/
input2:
echo preg_replace('/(^[A-Za-z])\d+(.*)/', '\1'.$newvalue.'\2', $str);
output2:
A
desired result:
A987:B17
NOTE: I need a regex solution, this applies to other similar problems.
You can use:
echo preg_replace('/(^[A-Za-z])\d+(.*)/', '${1}' . $newvalue . '${2}', $str);
//=> OUTPUT: A987:B17
Problem is that in your code back reference variable \1 is becoming \1987 and that's why showing empty value. ${1} keeps it separate from 987 and hence values are properly replaced.
anubhava's answer is great, but you could also use a lookbehind assertion like this:
echo preg_replace('/(?<=^[A-Za-z])\d+/', $newvalue, $str);
The lookbehind ensures that the matched string (\d+) immediately follows a string which matches the pattern, ^[A-Za-z]. However, unlike your original, the portion of the string which matches the lookbehind is not captured in the match, so the entire match is 12.
And just to provide yet another solution, you could also use a callback:
echo preg_replace_callback('/(^[A-Za-z])\d+/', function($m) use (&$newvalue) {
return $m[1].$newvalue;
}, $str);
I'm trying to script and parse a file,
Please help with regex in php to find and replace the following patterns:
From: "This is a foo[/www/bar.txt] within a foo[/etc/bar.txt]"
To: "This is a bar_txt_content within a bar2_txt_content"
Something along those lines:
$subject = "This is a foo[/www/bar.txt] within a foo[/etc/bar.txt]";
$pattern = '/regex-needed/';
preg_match($pattern, $subject, $matches);
foreach($matches as $match) {
$subject = str_replace('foo['.$match[0].']', file_get_contents($match[0]), $subject);
}
And my second request is to have:
From: 'This is a foo2[bar bar ] bar bar].'
To: "this is a returned"
Something along those lines:
$subject = 'This is a foo2[bar bar \] bar bar].';
$pattern = '/regex-needed/';
preg_match($pattern, $subject, $matches);
foreach($matches as $match) {
$subject = str_replace('foo2['.$match[0].']', my_function($match[0]), $subject);
}
Please help in constructing these patterns...
If you always have a structure like foo[ ... ]
Then is very easy:
foo\[([^]]+)\]
That is .NET syntax but i'm sure the expressions is simple enough for you to convert.
Description of the regex:
Match the characters “foo” literally «foo»
Match the character “[” literally «[»
Match the regular expression below and capture its match into backreference number 1 «([^]]+)»
Match any character that is NOT a “]” «[^]]+»
Between one and unlimited times, as many times as possible, giving back as needed (greedy) «+»
Match the character “]” literally «]»
Luc,
this should help you get started.
http://php.net/manual/en/function.preg-replace.php
You may have to setup a loop and increase the counter, using preg_replace with a limit of 1 to replace only the first instance.
In order to match foo[/www/bar.txt]:
the regex should be something like:
foo\[\/www\/([A-Za-z0-9]*)\.txt\]
The backslashes are there to cancel the special meaning of some characters in your regexp.
It will match foo[/www/.[some file name].txt, and ${1} will contain the filename without the .txt as brackets form groups which can be used in the replaced expression. ${1} will contain what was matched in the first round brackets, ${2} will contain what was matched in the second one, etc ...
Therefore your replaced expression should be something like "${1}_txt_content". Or in the second iteration "${1}2_txt_content".
[A-Za-z0-9]* means any alphanumeric character 0 or more times, you may want to replace the * with a + if you want at least 1 character.
So try:
$pattern = foo\[\/www\/([A-Za-z0-9]*)\.txt\];
$replace = "${1}_txt_content";
$total_count = 1;
do {
echo preg_replace($pattern, $replace, $subject, 1, $count);
$replace = "${1}" + ++$total_count + "_txt_content";
} while ($count != 0);
(warning, this is my first ever PHP program, so it may have mistakes as I cannot test it ! but I hope you get the idea)
Hope that helps !
Tony
PS: I am not a PHP programmer but I know this works in C#, for example, and looking at the PHP documentation it seems that it should work.
PS2: I always keep this website bookmarked for reference when I need it: http://www.regular-expressions.info/
$pattern = '/\[([^\]]+)\]/';
preg_match_all($pattern, $subject, $matches);
print_r($matches['1']);
found the correct regex I needed for escaping:
'/foo\[[^\[]*[^\\\]\]/'
Here is the regex I currently have (which kind of works):
$regex = '/[\w ]{7,30}/';
My revision looks like what I want, but it does not work at all:
$regex = '^[\w ]{7,30}$';
Here is how I am using the regex:
public function isValid( $value )
{
$regex = '/^[\w ]{7,30}$/';
return preg_match( $regex, $value ) ? true : false;
}
I am trying to match the following:
Any lower/upper case letter
Any digit
Can contain spaces
Cannot contain line breaks or tab space
Minimum of 7 characters
Maximum of 30 characters
Valid inputs:
Testing
Test ing
Test123
Test 123
Test___
Invalid inputs:
Testing#
Testin8+
Tester1&
The first regex will match all valid inputs, as well as invalid (as long as the first four characters are valid, it doesn't care about the rest). The second regex matches nothing.
Try combining both like so:
$regex = '/^[\w ]{7,30}$/';
Don't forget your delimiters:
/^[\w ]{7,30}$/
You're missing the / at the beginning and end.
$regex = '/^[\w ]{7,30}$/';
'/^[\w ]{7,30}$/'
You're missing the delimiters.