preg_replace does not replace the value as required - php

Assume we have a php array $row_mid, which contains strings like 'reaction_l0', 'reaction_l1', 'reaction_r0', 'reaction_r1' (in each case the number goes from 0 to 4. These strings are enclosed by <div> tags. I want to run a loop and remove these strings with preg_replace ():
$i = 0;
while ($i < count ($row_mid)){
$row_mid [$i] = preg_replace ("~^reaction_.[0-9]$~", "", $row_mid [$i]);
$i++;
}
The regexp ^reaction_.[0-9]$ was developed with the help of https://regex101.com/ and tested successfully with strings <div>reaction_r1</div> (no match, I need the tags stay where they are) and reaction_r1 (match). It doesn't work, however.

Get rid of the anchors, because they only allow the regexp to match the entire string, not when it's enclosed in tags.
$row_mid [$i] = preg_replace ("~reaction_.[0-9]~", "", $row_mid [$i]);

Just remove the two symbol ^ and $

Related

Stop regex splitting on whitespace

I'm writing a parser, trying to automate a way that I can pass any argument as a param like follows:
$content = '{loop for=products showPagination="true" paginationPosition="both" wrapLoop="true" returnDefaultNoResults="true" noResultsHeading="Nothing Found" noResultsHeadingSize="2" noResultsParagraph="We have not found any products in this category, please try another."}{/loop}';
preg_match_all('/([a-zA-Z]+)=([\/\.\"a-zA-Z0-9&;,_-]+)/', str_replace('"', '"', $content), $attr);
if (!is_array($attr)) return array();
for ($z = 0; $z < count($attr[1]); $z++) if (isset($attr['1'][$z])) $attrs[$attr['1'][$z]] = trim($attr['2'][$z], '"');
echo json_encode($attrs);
My Isssue is that my loop & regex is splitting out whitespace and I can't figure out how to alter it so that it doesn't.
I've tried adding \w into the right hand side of the = sign, but no luck.
RESULT
{"for":"products","showPagination":"true","paginationPosition":"both","wrapLoop":"true","returnDefaultNoResults":"true","noResultsHeading":"Nothing","noResultsHeadingSize":"2","noResultsParagraph":"We"}
You'll notice that the last two params both stop after the first word.
I suggest you to change the preg_match_all function like below.
preg_match_all('/([a-zA-Z]+)=("[^"]*"|\S+)/', str_replace('"', '"', $content), $attr);
It will greedily matches all the double quoted contents first. If there isn't any double quotes block, then it will match one or more non-space characters.
Output:
{"for":"products","showPagination":"true","paginationPosition":"both","wrapLoop":"true","returnDefaultNoResults":"true","noResultsHeading":"Nothing Found","noResultsHeadingSize":"2","noResultsParagraph":"We have not found any products in this category, please try another."}

remove a sentence in php string that contains certain words

I have the following string
"This is very nice. Thanks for your support."
Now I want to remove the line that contains Thanks word
you need to explode the paragraph by fullstop.
lets say your full paragraph is store in $str
$lines_arr = explode(".",$str);
now $lines_arr is an array contains numbers of lines.
now under loop you can check which lines contains "thanks" , if it is then skip it.
$string = '';
for($i=0; $i<(count($lines_arr)-1); $i++){
//with the help of strpos
if(strpos($lines_arr[$i],"Thanks") == false){
$string .= $lines_arr[$i].". ";
}
}
you can use str_replace
echo str_replace("Thanks", "", "This is very nice. Thanks for your support.");
# Output: This is very nice. for your support.
If you expect proper punctuation, you could explode() the string into an array on the full stops and delete the elements with your particular word, then merge all the elements back into a string.

preg_replace with arrays

My database has a table with 1000 terms and their definitions.
I want to print those definitions and add a span tag to every word that is already a term.
I use this to create the two arrays (patterns and replacements):
while($row = mysql_fetch_array($rsd)){
$patterns[$i] = '/'.$row['term'].'/';
$patterns[$i+1] = '/<span class="linkedterm"><span class="linkedterm">'.$row['term'].'</span>/';
$replacements[$i+1] = '<span class="linkedterm">'.$row['term'].'</span>';
$replacements[$i] = '<span class="linkedterm">'.$row['term'];
$i = $i + 2;
}
And this to echo the definitions:
echo preg_replace($patterns, $replacements, $row['definition']);
With this code i have an error for character /, at the close span tag. So I want a solution for this, to be able to pass a value with / char. Or any other solution that I may have missed.
Thanks
You might want to look at preg_quote
Quote regular expression characters
The / is also your delimiter character (to point out the start and end of your regex). So if you want to search for a literal /, make sure you escape it with a backslash, like so:
$patterns[$i+1] = '/<span class="linkedterm"><span class="linkedterm">'.$row['term'].'<\/span>/';
$patterns[$i] = '/'.preg_quote($row['term']).'/';
$patterns[$i+1] = '/'.preg_quote('<span class="linkedterm" ><span class="linkedterm" >'.$row['term'].'</span>', '/').'/';

Php is stripping one letter "g" from my rtrim function but not other chars

I'm trying to trim some youtube URLs that I am reading in from a playlist. The first 3 work fine and all their URLs either end in caps or numbers but this one that ends in a lower case g is getting trimmed one character shorter than the rest.
for ($z=0; $z <= 3; $z++)
{
$ythref2 = rtrim($tubeArray["feed"]["entry"][$z]["link"][0]["href"], '&feature=youtube_gdata');
The URL is http://www.youtube.com/watch?v=CuE88oVCVjg&feature=youtube_gdata .. and it should get trimmed down to .. http://www.youtube.com/watch?v=CuE88oVCVjg but instead it is coming out as http://www.youtube.com/watch?v=CuE88oVCVj.
I think it may be the ampersand symbol but I am not sure.
The second argument to rtrim is a list of characters to remove, not a string to remove.
You might want to use str_replace, or use parse_url and parse_str to get arrays of the components of the URL and the components of the query string, like "v".
Untested example code:
$youtube_url = 'http://www.youtube.com/watch?v=CuE88oVCVjg&feature=youtube_gdata';
$url_bits = parse_url($youtube_url);
$query_string = array();
parse_str($url_bits['query'], $query_string);
$video_identifier = $query_string['v']; // "CuE88oVCVjg"
$rebuilt_url = 'http://www.youtube.com/watch?v=' . $video_identifier;
No, it's the g in the second argument. rtrim() does not remove a string from the end, it removes any characters given in the second argument. Use preg_replace() or substr() instead.

Regular Expressions: how to do "option split" replaces

those reqular expressions drive me crazy. I'm stuck with this one:
test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not
Task:
Remove all [[ and ]] and if there is an option split choose the later one so output should be:
test1:link test2:silver test3:out1insideout2 test4:this|not
I came up with (PHP)
$text = preg_replace("/\\[\\[|\\]\\]/",'',$text); // remove [[ or ]]
this works for part1 of the task. but before that I think I should do the option split, my best solution:
$text = preg_replace("/\\[\\[(.*\|)(.*?)\\]\\]/",'$2',$text);
Result:
test1:silver test3:[[out1[[inside]]out2]] this|not
I'm stuck. may someone with some free minutes help me? Thanks!
I think the easiest way to do this would be multiple passes. Use a regular expression like:
\[\[(?:[^\[\]]*\|)?([^\[\]]+)\]\]
This will replace option strings to give you the last option from the group. If you run it repeatedly until it no longer matches, you should get the right result (the first pass will replace [[out1[[inside]]out2]] with [[out1insideout2]] and the second will ditch the brackets.
Edit 1: By way of explanation,
\[\[ # Opening [[
(?: # A non-matching group (we don't want this bit)
[^\[\]] # Non-bracket characters
* # Zero or more of anything but [
\| # A literal '|' character representing the end of the discarded options
)? # This group is optional: if there is only one option, it won't be present
( # The group we're actually interested in ($1)
[^\[\]] # All the non-bracket characters
+ # Must be at least one
) # End of $1
\]\] # End of the grouping.
Edit 2: Changed expression to ignore ']' as well as '[' (it works a bit better like that).
Edit 3: There is no need to know the number of nested brackets as you can do something like:
$oldtext = "";
$newtext = $text;
while ($newtext != $oldtext)
{
$oldtext = $newtext;
$newtext = preg_replace(regexp,replace,$oldtext);
}
$text = $newtext;
Basically, this keeps running the regular expression replace until the output is the same as the input.
Note that I don't know PHP, so there are probably syntax errors in the above.
This is impossible to do in one regular expression since you want to keep content in multiple "hierarchies" of the content. It would be possible otherwise, using a recursive regular expression.
Anyways, here's the simplest, most greedy regular expression I can think of. It should only replace if the content matches your exact requirements.
You will need to escape all backslashes when putting it into a string (\ becomes \\.)
\[\[((?:[^][|]+|(?!\[\[|]])[^|])++\|?)*]]
As others have already explained, you use this with multiple passes. Keep looping while there are matches, performing replacement (only keeping match group 1.)
Difference from other regular expressions here is that it will allow you to have single brackets in the content, without breaking:
test1:[[link]] test2:[[gold|si[lv]er]]
test3:[[out1[[in[si]de]]out2]] test4:this|not
becomes
test1:[[link]] test2:si[lv]er
test3:out1in[si]deout2 test4:this|not
Why try to do it all in one go. Remove the [[]] first and then deal with options, do it in two lines of code.
When trying to get something going favour clarity and simplicity.
Seems like you have all the pieces.
Why not just simply remove any brackets that are left?
$str = 'test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not';
$str = preg_replace('/\\[\\[(?:[^|\\]]+\\|)+([^\\]]+)\\]\\]/', '$1', $str);
$str = str_replace(array('[', ']'), '', $str);
Well, I didn't stick to just regex, because I'm of a mind that trying to do stuff like this with one big regex leads you to the old joke about "Now you have two problems". However, give something like this a shot:
$str = 'test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not'; $reg = '/(.*?):(.*?)( |$)/';
preg_match_all($reg, $str, $m);
foreach($m[2] as $pos => $match) {
if (strpos($match, '|') !== FALSE && strpos($match, '[[') !== FALSE ) {
$opt = explode('|', $match); $match = $opt[count($opt)-1];
}
$m[2][$pos] = str_replace(array('[', ']'),'', $match );
}
foreach($m[1] as $k=>$v) $result[$k] = $v.':'.$m[2][$k];
This is C# using only using non-escaped strings, hence you will have to double the backslashes in other languages.
String input = "test1:[[link]] " +
"test2:[[gold|silver]] " +
"test3:[[out1[[inside]]out2]] " +
"test4:this|not";
String step1 = Regex.Replace(input, #"\[\[([^|]+)\|([^\]]+)\]\]", #"[[$2]]");
String step2 = Regex.Replace(step1, #"\[\[|\]\]", String.Empty);
// Prints "test1:silver test3:out1insideout2 test4:this|not"
Console.WriteLine(step2);
$str = 'test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not';
$s = preg_split("/\s+/",$str);
foreach ($s as $k=>$v){
$v = preg_replace("/\[\[|\]\]/","",$v);
$j = explode(":",$v);
$j[1]=preg_replace("/.*\|/","",$j[1]);
print implode(":",$j)."\n";
}

Categories