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.
Related
I have some string, for example:
cats, e.g. Barsik, are funny. And it is true. So,
And I want to get as result:
cats, e.g. Barsik, are funny.
My try:
mb_ereg_search_init($text, '((?!e\.g\.).)*\.[^\.]');
$match = mb_ereg_search_pos();
But it gets position of second dot (after word "true").
How to get desired result?
Since a naive approach works for you, I am posting an answer. However, please note that detecting a sentence end is a very difficult task for a regex, and although it is possible to some degree, an NLP package should be used for that.
Having said that, I suggested using
'~(?<!\be\.g)\.(?=\s+\p{Lu})~ui'
The regex matches any dot (\.) that is not preceded with a whole word e.g (see the negative lookbehind (?<!\be\.g)), but that is followed with 1 or more whitespaces (\s+) followed with 1 uppercase Unicode letter \p{Lu}.
See the regex demo
The case insensitive i modifier does not impact what \p{Lu} matches.
The ~u modifier is required since you are working with Unicode texts (like Russian).
To get the index of the first occurrence, use a preg_match function with the PREG_OFFSET_CAPTURE flag. Here is a bit simplified regex you supplied in the comments:
preg_match('~(?<!т\.н)(?<!т\.к)(?<!e\.g)\.(?=\s+\p{L})~iu', $text, $match, PREG_OFFSET_CAPTURE);
See the lookaheads are executed one by one, and at the same location in string, thus, you do not have to additionally group them inside a positive lookahead. See the regex demo.
IDEONE demo:
$re = '~(?<!т\.н)(?<!т\.к)(?<!e\.g)\.(?=\s+\p{L})~iu';
$str = "cats, e.g. Barsik, are funny. And it is true. So,";
preg_match($re, $str, $match, PREG_OFFSET_CAPTURE);
echo $match[0][1];
Here are two approaches to get substring from start to second last . position of the initial string:
using strrpos and substr functions:
$str = 'cats, e.g. Barsik, and e.g. Lusya are funny. And it is true. So,';
$len = strlen($str);
$str = substr($str, 0, (strrpos($str, '.', strrpos($str, '.') - $len - 1) - $len) + 1);
print_r($str); // "cats, e.g. Barsik, and e.g. Lusya are funny."
using array_reverse, str_split and array_search functions:
$str = 'cats, e.g. Barsik, and e.g. Lusya are funny. And it is true. So,';
$parts = array_reverse(str_split($str));
$pos = array_search('.', $parts) + 1;
$str = implode("", array_reverse(array_slice($parts, array_search('.', array_slice($parts, $pos)) + $pos)));
print_r($str); // "cats, e.g. Barsik, and e.g. Lusya are funny."
I am trying to something like this.
Hiding users except for first 3 characters.
EX)
apple -> app**
google -> goo***
abc12345 ->abc*****
I am currently using php like this:
$string = "abcd1234";
$regex = '/(?<=^(.{3}))(.*)$/';
$replacement = '*';
$changed = preg_replace($regex,$replacement,$string);
echo $changed;
and the result be like:
abc*
But I want to make a replacement to every single character except for first 3 - like:
abc*****
How should I do?
Don't use regex, use substr_replace:
$var = "abcdef";
$charToKeep = 3;
echo strlen($var) > $charToKeep ? substr_replace($var, str_repeat ( '*' , strlen($var) - $charToKeep), $charToKeep) : $var;
Keep in mind that regex are good for matching patterns in string, but there is a lot of functions already designed for string manipulation.
Will output:
abc***
Try this function. You can specify how much chars should be visible and which character should be used as mask:
$string = "abcd1234";
echo hideCharacters($string, 3, "*");
function hideCharacters($string, $visibleCharactersCount, $mask)
{
if(strlen($string) < $visibleCharactersCount)
return $string;
$part = substr($string, 0, $visibleCharactersCount);
return str_pad($part, strlen($string), $mask, STR_PAD_RIGHT);
}
Output:
abc*****
Your regex matches all symbols after the first 3, thus, you replace them with a one hard-coded *.
You can use
'~(^.{3}|(?!^)\G)\K.~'
And replace with *. See the regex demo
This regex matches the first 3 characters (with ^.{3}) or the end of the previous successful match or start of the string (with (?!^)\G), and then omits the characters matched from the match value (with \K) and matches any character but a newline with ..
See IDEONE demo
$re = '~(^.{3}|(?!^)\G)\K.~';
$strs = array("aa","apple", "google", "abc12345", "asdddd");
foreach ($strs as $s) {
$result = preg_replace($re, "*", $s);
echo $result . PHP_EOL;
}
Another possible solution is to concatenate the first three characters with a string of * repeated the correct number of times:
$text = substr($string, 0, 3).str_repeat('*', max(0, strlen($string) - 3));
The usage of max() is needed to avoid str_repeat() issue a warning when it receives a negative argument. This situation happens when the length of $string is less than 3.
I have a string that contains many underscores followed by words ex: "Field_4_txtbox" I need to find the last underscore in the string and remove everything following it(including the "_"), so it would return to me "Field_4" but I need this to work for different length ending strings. So I can't just trim a fixed length.
I know I can do an If statement that checks for certain endings like
if(strstr($key,'chkbox')) {
$string= rtrim($key, '_chkbox');
}
but I would like to do this in one go with a regex pattern, how can I accomplish this?
The matching regex would be:
/_[^_]*$/
Just replace that with '':
preg_replace( '/_[^_]*$/', '', your_string );
There is no need to use an extremly costly regex, a simple strrpos() would do the job:
$string=substr($key,0,strrpos($key,"_"));
strrpos — Find the position of the last occurrence of a substring in a string
You can also just use explode():
$string = 'Field_4_txtbox';
$temp = explode('_', strrev($string), 2);
$string = strrev($temp[1]);
echo $string;
As of PHP 5.4+
$string = 'Field_4_txtbox';
$string = strrev(explode('_', strrev($string), 2)[1]);
echo $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");
Example
Input = 1.1.0.1
Expected output = 1.101
You could make use substr() and str_replace() fairly easily:
$str = '1.1.0.1';
$pos = strpos($str,'.');
if ($pos !== false) {
$str = substr($str,0,$pos+1) . str_replace('.','',substr($str,$pos+1));
}
echo $str;
$s = preg_replace('/((?<=\.)[^.]*)\./', '$1', $s);
Matches zero or more non-dot characters followed by a dot, but only if the match was preceded by a dot. This prevents a match on the initial digit(s). Replaces the match with only the non-dot characters (the digits), which were captured in group #1.
$input="1.1.1.1";
$s = explode(".",$input ) ;
$t=array_slice($s, 1);
print implode(".",array($s[0] , implode("",$t)) );
or
$input="1.1.1.1";
$s = explode(".",$input ,2) ;
$s[1]=str_replace(".","",$s[1]);
print implode(".",array($s[0] ,$s[1] ) );
Match&Release the first occurring literal dot
Replace all subsequent literal dots
Code: (Demo)
echo preg_replace('~^[^.]*\.(*SKIP)(*FAIL)|\.~', '', $string);
// 1.101
Or with the "continue" character (\G), consume and forget the first literal dot, then replace all subsequent literal dots.
Code: (Demo)
echo preg_replace('~(?:^[^.]*\.|\G(?!^))[^.]*\K\.~', '', $string);
// 1.101
Or simply check that a literal dot has a literal dot occurring earlier in the string.
Code: (Demo)
echo preg_replace('~(?<=\.)[^.]*\K\.~', '', $string);
// 1.101
I though substr_replace() would work here, but sadly no... Here is a regex approach:
$str = preg_replace('~(\d+\.)(\d+)\.(\d+)\.(\d+)~', '$1$2$3$4', $str);
You could also try the below regex with s switch,
<?php
$string = '1.1.0.1';
$pattern = "/(?s)((?<=\.).*?)(\.)/i";
$replacement = "$1";
echo preg_replace($pattern, $replacement, $string);
?>
Output:
1.101
Using regex matches can be clearer by depicting the desired result and avoids the error-prone approach of calls to substr and strpos. Here I assume that no text is required before the first dot, i.e., that an input may begin with a dot that must be preserved. The difference is whether a quantifier of * or + is appropriate in the patterns below.
If your inputs will always be short, a straightforward approach is to replace trailing dots until none remain:
$count = 0;
$output = $input;
do {
$output = preg_replace('/^(.*\.)(.+)\./', '$1$2', $output, -1, $count);
} while ($count != 0);
echo $output;
To do it with a single regex match, use preg_replace_callback to apply a function (str_replace in this case) to the backreference variable $2.
$output = preg_replace_callback(
'/^([^.]*\.)(.+)$/',
function ($m) { return $m[1] . str_replace('.', '', $m[2]); },
$input);
Sample results:
1.1.0.1 - 1.101
.1.0.1 - .101
111 - 111
1.1 - 1.1
1. - 1.
.1 - .1
.1. - .1
.... - .
You may want to experiment with the code and test cases at Try It Online!