How can remove the numberic suffix in php? - 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+)+$#';

Related

Remove empty space and plus sign from the beginning of a string

I have a string that begins with an empty space and a + sign :
$s = ' +This is a string[...]';
I can't figure out how to remove the first + sign using PHP. I've tried ltrim, preg_replace with several patterns and with trying to escape the + sign, I've also tried substr and str_replace. None of them is removing the plus sign at the beginning of the string. Either it doesn't replace it or it remplace/remove the totality of the string. Any help will be highly appreciated!
Edit : After further investigation, it seems that it's not really a plus sign, it looks 100% like a + sign but I think it's not. Any ideas for how to decode/convert it?
Edit 2 : There's one white space before the + sign. I'm using get_the_excerpt Wordpress function to get the string.
Edit 3 : After successfully removing the empty space and the + with substr($s, 2);, Here's what I get now :
$s == '#43;This is a string[...]'
Wiki : I had to remove 6 characters, I've tried substr($s, 6); and it's working well now. Thanks for your help guys.
ltrim has second parameter
$s = ltrim($s,'+');
edit:
if it is not working it means that there is sth else at the beginning of that string, eg. white spaces. You can check it by using var_dump($s); which shows you exactly what you have there.
You can use explode like this:
$result = explode('+', $s)[0];
What this function actually does is, it removes the delimeter you specify as a first argument and breaks the string into smaller strings whenever that delimeter is found and places those strings in an array.
It's mostly used with multiple ocurrences of a certain delimeter but it will work in your case too.
For example:
$string = "This,is,a,string";
$results = explode(',', $string);
var_dump($results); //prints ['This', 'is', 'a', 'string' ]
So in your case since the plus sign appears ony once the result is in the zero index of the returned array (that contains only one element, your string obviously)
Here's a couple of different ways I can think of
str_replace
$string = str_replace('+', '', $string);
preg_replace
$string = preg_replace('/^\+/', '', $string);
ltrim
$string = ltrim($string, '+');
substr
$string = substr($string, 1);
try this
<?php
$s = '+This is a string';
echo ltrim($s,'+');
?>
You can use ltrim() or substr().
For example :
$output = ltrim($string, '+');
or you can use
$output = substr($string, 1);
You can remove multiple characters with trim. Perhaps you were not re-assigning the outcome of your trim function.
<?php
$s = ' +This is a string[...]';
$s = ltrim($s, '+ ');
print $s;
Outputs:
This is a string[...]
ltrim in the above example removes all spaces and addition characters from the left hand side of the original string.

how to remove everything before second occurance of underscore

I couldn't find the solution using search.
I am looking for a php solution to remove all character BEFORE the second occurance of and underscore (including the underscore)
For example:
this_is_a_test
Should output as:
a_test
I currently have this code but it will remove everything after the first occurance:
preg_replace('/^[^_]*.s*/', '$1', 'this_is_a_test');
Using a slightly different approach,
$s='this_is_a_test';
echo implode('_', array_slice( explode( '_', $s ),2 ) );
/* outputs */
a_test
preg_replace('/^.*_.*_(.*)$/U', '$1', 'this_is_a_test');
Note the U modifier which tells regex to take as less characters for .* as possible.
You can also use explode, implode along with array_splice like as
$str = "this_is_a_test";
echo implode('_',array_splice(explode('_',$str),2));//a_test
Demo
Why go the complicated way? This is a suggestion though using strrpos and substr:
<?php
$str = "this_is_a_test";
$str_pos = strrpos($str, "_");
echo substr($str, $str_pos-1);
?>
Try this one.
<?php
$string = 'this_is_a_test';
$explode = explode('_', $string, 3);
echo $explode[2];
?>
Demo
I'm still in favor of a regular expression in this case:
preg_replace('/^.*?_.*?_/', '', 'this_is_a_test');
Or (which looks more complex here but is easily adjustable to N..M underscores):
preg_replace('/^(?:.*?_){2}/', '', 'this_is_a_test');
The use of the question mark in .*? makes the match non-greedy; and the pattern has been expanded from the original post to "match up through" the second underscore.
Since the goal is to remove text the matched portion is simply replaced with an empty string - there is no need for a capture group or to use such as the replacement value.
If the input doesn't include two underscores then nothing is removed; such can be adjusted, very easily with the second regular expression, if the rules are further clarified.

Removing all characters and numbers except last variable with dash symbol

Hi I want to remove a characters using preg_replace in php so i have this code here which i want to remove the whole characters, letters and numbers except the last digit(s) which has dash(-) symbol followed by a digits so here's my code.
echo preg_replace('/(.+)(?=-[0-9])|(.+)/','','asdf1245-10');
I expect the result will be
-10
the problem is above is not working very well. I checked the pattern using http://www.regextester.com/ it seems like it works, but on the other side http://www.phpliveregex.com/ doesn't work at all. I don't know why but anyone who can help to to figure it out?
Thanks a lot
Here is a way to go:
echo preg_replace('/^.+?(-[0-9]+)?$/','$1','asdf1245-10');
Output:
-10
and
echo preg_replace('/^.+?(-[0-9]+)?$/','$1','asdf124510');
Output:
<nothing>
My first thinking is to use explode in this case.. make it simple like the following code.
$string = 'asdf1245-10';
$array = explode('-', $string);
end($array);
$key = key($array);
$result = '-' . $array[$key];
$result => '-10';
An other way:
$result = preg_match('~\A.*\K-\d+\z~', $str, $m) ? $m[0] : '';
pattern details:
\A # start of the string anchor
.* # zero or more characters
\K # discard all on the left from match result
-\d+ # the dash and the digits
\z # end of the string anchor
echo preg_replace('/(\w+)(-\w+)/','$2', 'asdf1245-10');

Match pattern and exclude substrings with preg_match_all

I need to find all the strings placed between START and END, escluding PADDING substring from matched string. The best way I've found is
$r="stuffSTARTthisPADDINGisENDstuffstuffSTARTwhatPADDINGIwantPADDINGtoPADDINGfindENDstuff" ;
preg_match_all('/START(.*?)END/',str_replace('PADDING','',$r),$m);
print(join($m[1]));
> thisiswhatIwanttofind
I want to do this with the smallest code size possible: there a shorter with only preg_match_all and no str_replace, that eventually returns directly the string without join arrays? I've tried with some lookaround expressions but I can't find the proper one.
$r="stuffSTARTthisPADDINGisENDstuffstuffSTARTwhatPADDINGIwantPADDINGtoPADDINGfindENDstuff";
echo preg_replace('/(END.*?START|PADDING|^[^S]*START|END.*$)/', '', $r);
This should return you thisiswhatIwanttofind using a single regular expression pattern
Explanation:-
END.*?START # Replace occurrences of END to START
PADDING # Replace PADDING
^[^S]*START # Replace any character until the first START (inclusive)
END.*$ # Replace the last END and until end of the string
$r="stuffSTARTthisPADDINGisENDstuffstuffSTARTwhatPADDINGIwantPADDINGtoPADDINGfindENDstuff" ;
preg_match_all('/(?:START)(.*?)(?:END)/',str_replace('PADDING','',$r),$m);
var_dump(implode(' ',$m[1]));
would work but I guess you want something faster.
You can also use use preg_replace_callback like this:
$str = preg_replace_callback('#.*?START(.*?)END((?!.*?START.*?END).*$)?#',
function ($m) {
print_r($m);
return str_replace('PADDING', '', $m[1]);
}, $r);
echo $str . "\n"; // prints thisiswhatIwanttofind

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.

Categories