Find and replace starting from the end [duplicate] - php

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Preg Replace - replace second occurance of a match
I have a string that includes the word rules twice. I need to find and replace the 2nd word. Tried fooling around with str_replace() but couldn't get anything, the 4th parameter wasn't what I expected.
Here is an example string:
http://localhost/proj1/modstart/admin/index.php?i=rules&sid=397ab1f6b8eb8a17787438a7e2e60ea3&mode=rules
After my replace it should look like this:
http://localhost/proj1/modstart/admin/index.php?i=rules&sid=397ab1f6b8eb8a17787438a7e2e60ea3&mode=manage
I read that preg_replace() could help, but I don't know how to write patterns.
Ideas?
P.S: Don't suggest splitting the string into two variables, that wouldn't serve my needs.

It would be a very good idea to learn about regular expressions. In PHP, you can accomplish your find/replace like this:
$result = preg_replace('/(rules.*?)rules/','$1manage',$str,1);
It basically finds "rules" once, then anything, then rules a second time, then puts it all back before the second match and replaces the word.

To not use a regular expression, and also to not store anything into a second variable, you could use str_replace() with a little magic from strpos():
$string = substr($string, 0, strpos($str, 'rules') + 5) . str_replace('rules', 'whatever', substr($string, strpos($string, 'rules') + 5));
This will take the full string up-to the end of the first instance of rules and then do the string-replacement on the second-part of the string which will contain any other instance of the word.
The same thing, but a little more cleaner (yes, by using a second variable):
$pos = strpos($string, 'rules') + 5;
$string = substr($string, 0, $pos) . str_replace('rules', 'whatever', substr($string, $pos));
If the word to find+replace is dynamic or you want to use a different word on different pages, you could make that a variable, like this:
$findMe = 'rules';
$replaceWith = 'whatever';
$pos = strpos($string, $findMe) + strlen($findMe);
$string = substr($string, 0, $pos) . str_replace($findMe, $replaceWith, substr($string, $pos));

You should use regex >>
$new = preg_replace('/\brules\b(?!.*\brules\b)/', 'manage', $old);
It is a good idea to use word boundaries \b, so it will not match some larger strings that contain "rules", such as "preudorules".
Negative lookahead (?!.*\brules\b) ensures there is no other word "rules" behind, so the one you are replacing is the last one.

Related

How can remove the numberic suffix in php?

For example, if I want to get rid of the repeating numeric suffix from the end of an expression like this:
some_text_here_1
Or like this:
some_text_here_1_5
and I want finally receive something like this:
some_text_here
What's the best and flexible solution?
$newString = preg_replace("/_?\d+$/","",$oldString);
It is using regex to match an optional underscore (_?) followed by one or more digits (\d+), but only if they are the last characters in the string ($) and replacing them with the empty string.
To capture unlimited _ numbers, just wrap the whole regex (except the $) in a capture group and put a + after it:
$newString = preg_replace("/(_?\d+)+$/","",$oldString);
If you only want to remove a numberic suffix if it is after an underscore (e.g. you want some_text_here14 to not be changed, but some_text_here_14 to be changed), then it should be:
$newString = preg_replace("/(_\d+)+$/","",$oldString);
Updated to fix more than one suffix
Strrpos is far better than regex on such a simple string problem.
$str = "some_text_here_13_15";
While(is_numeric(substr($str, strrpos($str, "_")+1))){
$str = substr($str,0 , strrpos($str, "_"));
}
Echo $str;
Strrpos finds the last "_" in str and if it's numeric remove it.
https://3v4l.org/OTdb9
Just to give you an idea of what I mean with regex not being a good solution on this here is the performance.
Regex:
https://3v4l.org/Tu8o2/perf#output
0.027 seconds for 100 runs.
My code with added numeric check:
https://3v4l.org/dkAqA/perf#output
0.003 seconds for 100 runs.
This new code performs even better than before oddly enough, regex is very slow. Trust me on that
You be the judge on what is best.
First you'll want to do a preg_replace() in order to remove all digits by using the regex /\d+/. Then you'll also want to trim any underscores from the right using rtrim(), providing _ as the second parameter.
I've combined the two in the following example:
$string = "some_text_here_1";
echo rtrim(preg_replace('/\d+/', '', $string), '_'); // some_text_here
I've also created an example of this at 3v4l here.
Hope this helps! :)
$reg = '#_\d+$#';
$replace = '';
echo preg_replace($reg, $replace, $string);
This would do
abc_def_ghi_123 > abc_def_ghi
abc_def_1 > abc_def
abc_def_ghi > abc_def_ghi
abd_def_ > abc_def_
abc_123_def > abd_123_def
in case of abd_def_123_345 > abc_def
one could change the line
$reg = '#(?:_\d+)+$#';

PHP wrapping last two letters of string with HTML

I am running into a problem trying to do a replacement on a few strings. Essentially what I have is a bunch of prices on my page that look like
RMB148.00
What i am trying to do is run a replace on only the last 2 numbers so i can do something like
RMB14800
Preg replace works fine for the RMB part because it is always there.
My problem is the last two numbers can be anything it all depends on the price so I cant just remove and replace, I need to just wrap HTML <sup> tags around them.
$string = $product['price'];
$string = preg_replace('/[\x00-\x1F\x80-\xFF]/', '', $string);
echo preg_replace('/RMB/', '<sup class="currency-sym">RMB</sup>', $string, 1);
Assuming the last two characters are digits, you could just
$string=preg_replace('/(\d\d)$/', '<sup class="currency-sym">\1</sup>', $string);
If not,
$string=preg_replace('/(..)$/', '<sup class="currency-sym">\1</sup>', $string);
should do the trick.
Alternativly use
$string=substr($string,0,-2).'<sup class="currency-sym">'.substr($string,-2).'</sup>';
Here is a regex solution that looks for the final digit notation at the end of your string.
$string = 'RMB148.00';
$string = preg_replace('/(\d+)\.(\d{2})\z/','$1<sup>$2</sup>',$string);
echo $string;
You could use the following with the explode () function
$string = explode ('.', $product['price']);
$new_string = $string[0].'<sup>'. $string [1]. '</sup>';
And do the regex for the RMB the same way.
Code.
<?php
$string = '14842.00';
$string = substr($string, 0, strlen($string) - 2) . '<sup>' . substr($string, strlen($string) - 2, 2) . '</sup>';
echo $string;
Try online sandbox.
Explanation.
substr($s, $i, $l) gets $l symbols of $s, started from $i index (indexes starts from zero).
So first substr($string, 0, strlen($string) - 2) gets all string except last two symbols.
Second substr($string, strlen($string) - 2, 2) gets only last two symbols.
More about substr.
You should use a pattern matching regex. Note the $1 in the replacement argument matches (\d{2}) in the pattern argument. preg_replace() only replaces the matched pattern. This pattern matches . followed by any two digits. Since . is not included in the replacement argument it does not show up in your $string.
$string = preg_replace('/\.(\d{2})$/', '<sup>$1</sup>', $string);
Of course, you could use one preg_replace to do what you want:
$string = preg_replace('/^(RMB)(\d+)(\.(\d{2}))?$/', "<sup class='currency-sym'>$1</sup>$2<sup>$4</sup>", $string);
The second example may be a good idea if you want DOM integrity, otherwise it creates an empty <sup></sup> when there is no decimal.

Parse text between 2 words

For sure this has already been asked by someone else, however I've searched here on SO and found nothing https://stackoverflow.com/search?q=php+parse+between+words
I have a string and want to get an array with all the words contained between 2 delimiters (2 words). I am not confident with regex so I ended up with this solution, but it is not appropiate because I need to get all the words that match those requirements and not only the first one.
$start_limiter = 'First';
$end_limiter = 'Second';
$haystack = $string;
# Step 1. Find the start limiter's position
$start_pos = strpos($haystack,$start_limiter);
if ($start_pos === FALSE)
{
die("Starting limiter ".$start_limiter." not found in ".$haystack);
}
# Step 2. Find the ending limiters position, relative to the start position
$end_pos = strpos($haystack,$end_limiter,$start_pos);
if ($end_pos === FALSE)
{
die("Ending limiter ".$end_limiter." not found in ".$haystack);
}
# Step 3. Extract the string between the starting position and ending position
# Our starting is the position of the start limiter. To find the string we must take
# the ending position of our end limiter and subtract that from the start limiter
$needle = substr($haystack, $start_pos+1, ($end_pos-1)-$start_pos);
echo "Found $needle";
I thought also about using explode() but I think a regex could be better and faster.
I'm not much familiar with PHP, but it seems to me that you can use something like:
if (preg_match("/(?<=First).*?(?=Second)/s", $haystack, $result))
print_r($result[0]);
(?<=First) looks behind for First but doesn't consume it,
.*? Captures everything in between First and Second,
(?=Second) looks ahead for Second but doesn't consume it,
The s at the end is to make the dot . match newlines if any.
To get all the text between those delimiters, you use preg_match_all and you can use a loop to get each element:
if (preg_match_all("/(?<=First)(.*?)(?=Second)/s", $haystack, $result))
for ($i = 1; count($result) > $i; $i++) {
print_r($result[$i]);
}
Not sure that the result will be faster than your code, but you can do it like this with regex:
$pattern = '~(?<=' . preg_quote($start, '~')
. ').+?(?=' . preg_quote($end, '~') . ')~si';
if (preg_match($pattern, $subject, $match))
print_r($match[0]);
I use preg_quote to escape all characters that have a special meaning in a regex (like +*|()[]{}.? and the pattern delimiter ~)
(?<=..) is a lookbehind assertion that check a substring before what you want to find.
(?=..) is a lookahead assertion (same thing for after)
.+? means all characters one or more times but the less possible (the question mark make the quantifier lazy)
s allows the dot to match newlines (not the default behavior)
i make the search case insensitive (you can remove it, if you don't need)
This allows you to run the same function with different parameters, just so you don't have to rewrite this bit of code all of the time. Also uses the strpos which you used. Has been working great for me.
function get_string_between($string, $start, $end){
$string = " ".$string;
$ini = strpos($string,$start);
if ($ini == 0) return "";
$ini += strlen($start);
$len = strpos($string,$end,$ini) - $ini;
return substr($string,$ini,$len);
}
$fullstring = 'This is a long set of words that I am going to use.';
$parsed = get_string_between($fullstring, 'This', "use");
echo $parsed;
Will output:
is a long set of words that I am going to
Here's a simple example for finding everything between the words 'mega' and 'yo' for the string $t.
PHP Example
$t = "I am super mega awesome-sauce, yo!";
$arr = [];
preg_match("/mega\ (.*?)\ yo/ims", $t, $arr);
echo $arr[1];
PHP Output
awesome-sauce,
You can also use two explode statements.
For example, say you want to get "z" in y=mx^z+b. To get z:
$formula="y=mx^z+b";
$z=explode("+",explode("^",$formula)[1])[0];
First I get everything after ^: explode("^",$formula)[1]
Then I get everything before +: explode("+",$previousExplode)[0]

Replace after a needle in a string?

I have a string, something like
bbbbabbbbbccccc
Are there any way for me to replace all the letters "b" after the only one letter "a" into "c" without having to split the string, using PHP?
bbbbacccccccccc
odd question.
echo preg_replace('/a(.*)$/e', "'a'.strtr($1, 'b', 'c')", 'bbbabbbbbccccc');
preg_replace matches everything to the right of 'a' with regex. the e modifier in the regex evaluates the replacement string as code. the code in the replacement string uses strtr() to replace 'b's with 'c's.
Here are three options.
First, a split. Yes, I know you want to do it without a split.
$string = 'bbbbabbbbbccccc';
$parts = preg_split('/(a)/', $string, 2, PREG_SPLIT_DELIM_CAPTURE);
// Parts now looks like:
// array('bbb', 'a', 'bbbbcccc');
$parts[2] = str_replace('b', 'c', $parts[2]);
$correct_string = join('', $parts);
Second, a position search and a substring replacement.
$string = 'bbbbabbbbbccccc';
$first_a_index = strpos($string, 'a');
if($first_a_index !== false) {
// Now, grab everything from that first 'a' to the end of the string.
$replaceable = substr($string, $first_a_index);
// Replace it.
$replaced = str_replace('b', 'c', $replaceable );
// Now splice it back in
$string = substr_replace($string, $replaced, $first_a_index);
}
Third, I was going to post a regex, but the one dqhendricks posted is just as good.
These code examples are verbose for clarity, and can be reduced to one-or-two-liners.
$s = 'bbbbabbbbbccccc';
echo preg_replace('/((?:(?!\A)\G|(?<!a)a(?!a))[^b]*)b/', '$1c', $s);
\G matches the position where the previous match ended. On the first match attempt, \G matches the beginning of the string like \A. We don't want that, so we use (?!\A) to prevent it.
(?<!a)a(?!a) matches an a that's neither preceded nor followed by an a. The a is captured in group #1 so we can plug it back into the replacement with $1.
This is a "pure regex" solution, meaning it does the whole job in one call to preg_replace and doesn't rely on embedded code and the /e modifier. It's good to know in case you ever find yourself working within those constraints, but it definitely shouldn't be your first resort.

First instance in string

I have a string, say:
www.google.com/tomato.mdm
I need to replace tomato with tomaton (add n to it). My method is to find the . then replace it with n. . This didn't work. Tomato can be many differeny words, so I can't just search for that either...
Is their any way to solve this?
I thought about only replacing it at the first instance from the end, but cannot find a function to do this in the php manuel.
I would approach it like this:
$string = "www.google.com/tomato.mdm";
$lastDot = strrpos($string, '.');
$newString = substr($string, 0, $lastDot) . 'n.' . substr($string, $lastDot + 1);
I use strrpos to find the last occurrence of "." in the string. Then I split the string in two parts (using substr): Everything before the last dot, and everything after it. I then insert "n." between those two parts, which should give the desired result.
A solution using regular expression would be the following:
$string = "www.google.com/tomato.mdm";
$newString = preg_replace('/(.*?)(\.[^\.]*)$/', '\1n\2', $string);
See preg_replace and a regex reference for more info.
You should use Regex to do this
$newStr = preg_replace("#^(www.google.com/[a-zA-z]*)#", '$1n', "www.google.com/tomato.mdm");

Categories