How to make preg_replace not hungry? [duplicate] - php

This question already has answers here:
What is the difference between .*? and .* regular expressions?
(3 answers)
Closed 4 years ago.
I have a string:
$str = '{:de}Hallo Welt{:}{:en}Helo world{:}';
now i need to get substring for setted language.
$placeholder = '{:en}';
$lang_content = preg_replace('/(.*)'.preg_quote($placeholder).'(.*)'.preg_quote('{:}').'(.*)/sm', '\2', $str);
in case of value for placeholder {:en} i get Helo world as value for $lang_content, it works fine, but in case {:de} i get Hallo Welt{:}{:en}Helo world.
How can it be fixed? thanx!

You need to make the regex lazy by adding a ? in the second capture.
$str = '{:de}Hallo Welt{:}{:en}Helo world{:}';
$placeholder = '{:de}';
$lang_content = preg_replace('/(.*)'.preg_quote($placeholder).'(.*?)'.preg_quote('{:}').'(.*)/sm', '\2', $str);
echo $lang_content; // Hallo Welt
https://3v4l.org/m6AGF
An optional method would be to use preg_match to get an associative array.
$str = '{:de}Hallo Welt{:}{:en}Helo world{:}';
preg_match_all("/\{:(.*?)}(.*?)\{/", $str, $matches);
$matches = array_combine($matches[1], $matches[2]);
var_dump($matches);
echo $matches["de"]; // Hallo Welt
https://3v4l.org/ELB2B

With the Ungreedy flag (U).
You can update the flags at the end of your regex from /sm to /smU for the result to stop at the next occurrence of {:} in the string and not at the last one.
If the string is to contain several occurrences, maybe you can also add the global (g) flag so the regex doesn't stop after the first one.
You can test it here: https://regex101.com/r/4XSPoz/3
By the way, it seems that your are using preg_replace as a way to find a substring and don't actually need to replace it in the result, maybe you should use preg_match instead.

Related

Regex to put missing quotes around keys of arrays [duplicate]

This question already has answers here:
How to fix associative array keys that lack single quotation marks in multiple files
(4 answers)
Closed 7 months ago.
I try to correct my PHP-code and add to the quotes ' around the keys of the arrays in my source-code.
I have like 10,000 files to correct. Can I use some regular expressions to achieve that?
I tried to use this regular expression, but it is not perfect:
\$([0-9a-zA-z_\-]+)\[([0-9a-zA-z_\-]+)\]\[([0-9a-zA-z_\-]+)\]
to
\$$1['$2']['$3']
Example of what I want to change:
$_SESSION[Name][name_2] to $_SESSION['Name']['name_2']
$_POST[Name][na-me_2] to $_SESSION['Name']['na-me_2']
$_GET[Name][na-me_2] to $_GET['Name']['na-me_2']
$tab[name_one] to $tab['name_one']
We can most likely capture our indices with a group, then preg_replace it, maybe with an expression similar to:
\[(.+?)\]
Test
$re = '/\[(.+?)\]/m';
$str = '$_SESSION[Name][name_2]
$_POST[Name][na-me_2]
$_GET[Name][na-me_2]
$tab[name_one]';
$subst = '[\'$1\']';
$result = preg_replace($re, $subst, $str);
echo $result;
RegEx
If this expression wasn't desired, it can be modified/changed in regex101.com.
RegEx Circuit
jex.im visualizes regular expressions:
If we wish to have more constraints, we can surely update this expression. For example, if we would have already had keys with ' or ", then we can just add a new boundary such as all chars except ' and " in a char class:
[^'"]*
and our expression would become:
\[([^'"]*?)\]
Demo
Test
$re = '/\[([^\'"]*?)\]/m';
$str = '$_SESSION[Name][name_2]
$_POST[Name][na-me_2]
$_GET[\'Name\'][na-me_2]
$tab[name_one]
$_POST[Name]["na-me_2"]
$_POST[\'Name\']["na-me_2"]';
$subst = '[\'$1\']';
$result = preg_replace($re, $subst, $str);
echo $result;
Output
$_SESSION['Name']['name_2']
$_POST['Name']['na-me_2']
$_GET['Name']['na-me_2']
$tab['name_one']
$_POST['Name']["na-me_2"]
$_POST['Name']["na-me_2"]

How to get the words that start with '#' in string using php? [duplicate]

This question already has answers here:
Retrieve all hashtags from a tweet in a PHP function
(5 answers)
Closed 6 years ago.
I have this sentence
"My name's #jeff,what is thy name?"
And now i want to get #jeff from this sentence.
I have tried this code
for ($i=0; $i <=substr_count($Text,'#'); $i++) {
$a=explode('#', $Text);
echo $a[$i];
}
But it returns #jeff,what is thy name? which is not what my soul desires
There is simpler solution to do it. Use preg_match() that find target part of string using regex.
preg_match("/#\w+/", $str, $matches);
echo $matches[0]
Check result of code in demo
If you want to get all matches string, use preg_match_all() that find all matches.
preg_match_all("/#\w+/", $str, $matches);
print_r($matches[0]);
Personally I would not capture the word with #, since a hashtag is only an identifier for your code to get the attached word.
$re = '/(?<!\S)#([A-Za-z_][\w_]*)/';
$str = "My name's #jeff,what #0is #thy name?";
preg_match_all($re, $str, $matches);
// Print the entire match result
print_r($matches[0]); // #jeff, #thy
print_r($matches[1]); // jeff, thy
By the rules of hashtags, it may not start with a digit but may contain them.

Count of exact characters in string [duplicate]

This question already has answers here:
Count exact substring in a string in php
(3 answers)
Closed 3 years ago.
I'm trying to count the number of occurrences of a character in a string.
for example:
$string = "ab abc acd ab abd";
$chars = "ab";
How many times does $chars exactly appears in $string, and the right answer is 2 times, but with substr_count() it returns 3 times !!!
Is there any PHP function or Regex that return the right answer ?
with regex you can do the following:
$count = preg_match_all('/\bab\b/', $string);
it will count occurrencies of the word "ab". \b in the regular expression means position between a non-word character and a word character.
A "word" character is any letter or digit or the underscore character.
To what you have said in comments already, you are not trying to find an exact word since a word has specific boundaries. So what you are trying to do is something like this:
/(?:\A|[^H])HH(?:[^H]|\z)/g
preg_match_all('/(\A|[^H])HH([^H]|\z)/', $string, $matches);
or with question's example:
/(?:\A|[^a])ab(?:[^b]|\z)/g
preg_match_all('/(?:\A|[^a])ab(?:[^b]|\z)/', $string, $matches);
Explanation:
(?: \A | [^a] ) # very beginning of the input string OR a character except `a`
ab # match `ab`
(?: [^b] | \z ) # end of the input string OR a character except `b`
Live demo
Above was a simple understanding of what should be done but it's more than better to use a solution that is made for this specific purpose, named lookarounds:
/(?<!a)ab(?!b)/g
preg_match_all('/(?<!a)ab(?!b)/', $string, $matches);
There's a few ways. Regex as above, or using simple PHP instead:
$string = 'ab abc acd ab abd';
$chars = 'ab';
$strings = explode(" ", $string);
echo array_count_values($strings)[$chars];
// Outputs 2
// IF you don't have php 5.6:
$values = array_count_values($strings);
echo $values[$chars];
// Outputs 2

how to use php sscanf with ampersand character [duplicate]

This question already has answers here:
Parsing URL query in PHP [duplicate]
(5 answers)
Closed 1 year ago.
I use php function sscanf to parse string and extrac parameters.
This code :
$s='myparam1=hello&myparam2=world';
sscanf($s, 'myparam1=%s&myparam2=%s', $s1, $s2);
var_dump($s1, $s2);
displays :
string(20) "hello&myparam2=world" NULL
but i would like string hello in $s1 and strin world in $s2.
Any help?
%s isn't an equivalent to \w in regexp: it doesn't pick up only alphanumerics
$s='myparam1=hello&myparam2=world';
sscanf($s, 'myparam1=%[^&]&myparam2=%s', $s1, $s2);
var_dump($s1, $s2);
but using parse_str() might be a better option for you in this case
$s='myparam1=hello&myparam2=world';
parse_str($s, $sargs);
var_dump($sargs['myparam1'], $sargs['myparam2']);
How about using regular expressions?
Here is an example:
$string = 'myparam1=hello&myparam2=world';
// Will use exactly the same format
preg_match('/myparam1=(.*)&myparam2=(.*)/', $string, $matches);
var_dump($matches); // Here ignore first result
echo("<br /><br />");
// Will match two values no matter of the param name
preg_match('/.*=(.*)&.*=(.*)/', $string, $matches);
var_dump($matches); // Here ignore first result too
echo("<br /><br />");
// Will match all values no matter of the param name
preg_match('/=([^&]*)/', $string, $matches);
var_dump($matches);
I all three cases the matches array will contain the params.
I'm pretty convinced that it's better.
Good luck!

PHP: Best method to extract numbers from a string [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
a simple function for return number from string in php
What's the best/most efficient method to extract a specific set of numbers from a string? For example: I want to get the set of numbers immediately after Case# in sring "blah blah Case#004522 blah blah". I imagine the number of numeric characters after Case# will always be the same but I would like the code to not make that assumption as I have been.
So far I have been using a strpos method to locate Case# and then pull a specific number of characters afterwords using substr. I just feel like this is clunky. Maybe preg_match would be more effective or simplified?
$text = "blah blah Case#004552 blah blah";
$find = strpos($text,'Case#');
if ( $find )
$numbers = substr($text, $find+5, 6);
You can make use of regular expressions to first match your pattern of characters (Case#) and then you expect to match numbers only (digits), that is \d in PCRE (Demo):
$numbers = preg_match("/Case#(\d+)/", $text, $matches)
? (int)$matches[1]
: NULL
;
unset($matches);
For multiple (integer) matches at once:
$numbers = preg_match_all("/Case#(\d+)/", $text, $matches)
? array_map('intval', $matches[1])
: NULL
;
unset($matches);
You can locate it as you do it already, and then scan for the number (Demo):
$find = strpos($text, 'Case#');
sscanf(substr($text, $find), 'Case#%d', $numbers);
Use PHP's preg_match and following regex:
(?<=case#)[0-9]+
You can test # http://regexr.com?31jdv
The simplest solution is
if (preg_match('/Case#\s*(\d+)/i', $test, $m)) {
$numbers = $m[1];
}

Categories