Well im trying to replace the first number in a string in PHP, but not behaves as spected.
$str = 'A12:B17';
$newvalue = '987';
echo preg_replace('/(^[A-Za-z])\d+(.*)/', '\1'.$newvalue.'\2', $str);
The problem is \1 is well replaced when i put it alone, but when i put $newvalue and \2 the first \1 is ignored
input1:
echo preg_replace('/(^[A-Za-z])\d+(.*)/', '\1'.$newvalue.'\2', $str);
output1:
87:B17 // dissapears first character :/
input2:
echo preg_replace('/(^[A-Za-z])\d+(.*)/', '\1'.$newvalue.'\2', $str);
output2:
A
desired result:
A987:B17
NOTE: I need a regex solution, this applies to other similar problems.
You can use:
echo preg_replace('/(^[A-Za-z])\d+(.*)/', '${1}' . $newvalue . '${2}', $str);
//=> OUTPUT: A987:B17
Problem is that in your code back reference variable \1 is becoming \1987 and that's why showing empty value. ${1} keeps it separate from 987 and hence values are properly replaced.
anubhava's answer is great, but you could also use a lookbehind assertion like this:
echo preg_replace('/(?<=^[A-Za-z])\d+/', $newvalue, $str);
The lookbehind ensures that the matched string (\d+) immediately follows a string which matches the pattern, ^[A-Za-z]. However, unlike your original, the portion of the string which matches the lookbehind is not captured in the match, so the entire match is 12.
And just to provide yet another solution, you could also use a callback:
echo preg_replace_callback('/(^[A-Za-z])\d+/', function($m) use (&$newvalue) {
return $m[1].$newvalue;
}, $str);
Related
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.
I want to manipulate a string like "...4+3(4-2)-...." to become "...4+3*(4-2)-....", but of course it should recognize any number, d, followed by a '(' and change it to 'd*('. And I also want to change ')(' to ')*(' at the same time if possible. Would nice if there is a possibility to add support for constants like pi or e too.
For now, I just do it this stupid way:
private function make_implicit_multiplication_explicit($string)
{
$i=1;
if(strlen($string)>1)
{
while(($i=strpos($string,"(",$i))!==false)
{
if(strpos("0123456789",substr($string,$i-1,1)))
{
$string=substr_replace($string,"*(",$i,1);
$i++;
}
$i++;
}
$string=str_replace(")(",")*(",$string);
}
return $string;
}
But I Believe this could be done much nicer with preg_replace or some other regex function? But those manuals are really cumbersome to grasp, I think.
Let's start by what you are looking for:
either of the following: ((a|b) will match either a or b)
any number, \d
the character ): \)
followed by (: \(
Which creates this pattern: (\d|\))\(. But since you want to modify the string and keep both parts, you can group the \( which results in (\() making it worse to read but better to handle.
Now everything left is to tell how to rearrange, which is simple: \\1*\\2, leaving you with code like this
$regex = "/(\d|\))(\()/";
$replace = "\\1*\\2";
$new = preg_replace($regex, $replace, $test);
To see that the pattern actually matches all cases, see this example.
To recognize any number followed by a ( OR a combination of a )( and place an asterisk in between them, you can use a combination of lookaround assertions.
echo preg_replace("/
(?<=[0-9)]) # look behind to see if there is: '0' to '9', ')'
(?=\() # look ahead to see if there is: '('
/x", '*', '(4+3(4-2)-3)(2+3)');
The Positive Lookbehind asserts that what precedes is either a number or right parentheses. While the Positive Lookahead asserts that the preceding characters are followed by a left parentheses.
Another option is to use the \K escape sequence in replace of the Lookbehind. \K resets the starting point of the reported match. Any previously consumed characters are no longer included ( throws away everything that it has matched up to that point. )
echo preg_replace("/
[0-9)] # any character of: '0' to '9', ')'
\K # resets the starting point of the reported match
(?=\() # look ahead to see if there is: '('
/x", '*', '(4+3(4-2)-3)(2+3)');
Your php code should be,
<?php
$mystring = "4+3(4-2)-(5)(3)";
$regex = '~\d+\K\(~';
$replacement = "*(";
$str = preg_replace($regex, $replacement, $mystring);
$regex1 = '~\)\K\(~';
$replacement1 = "*(";
echo preg_replace($regex1, $replacement1, $str);
?> //=> 4+3*(4-2)-(5)*(3)
Explanation:
~\d+\K\(~ this would match the one or more numbers followed by a (. Because of \K it excludes the \d+
Again it replaces the matched part with *( which in turn produces 3*( and the result was stored in another variable.
\)\K\( Matches )( and excludes the first ). This would be replaced by *( which in turn produces )*(
DEMO 1
DEMO 2
Silly method :^ )
$value = '4+3(4-2)(1+2)';
$search = ['1(', '2(', '3(', '4(', '5(', '6(', '7(', '8(', '9(', '0(', ')('];
$replace = ['1*(', '2*(', '3*(', '4*(', '5*(', '6*(', '7*(', '8*(', '9*(', '0*(', ')*('];
echo str_replace($search, $replace, $value);
I am trying to make a regex that will look behind .txt and then behind the "-" and get the first digit .... in the example, it would be a 1.
$record_pattern = '/.txt.+/';
preg_match($record_pattern, $decklist, $record);
print_r($record);
.txt?n=chihoi%20%283-1%29
I want to write this as one expression but can only seem to do it as two. This is the first time working with regex's.
You can use this:
$record_pattern = '/\.txt.+-(\d)/';
Now, the first group contains what you want.
Your regex would be,
\.txt[^-]*-\K\d
You don't need for any groups. It just matches from the .txt and upto the literal -. Because of \K in our regex, it discards the previously matched characters. In our case it discards .txt?n=chihoi%20%283- string. Then it starts matching again the first digit which was just after to -
DEMO
Your PHP code would be,
<?php
$mystring = ".txt?n=chihoi%20%283-1%29";
$regex = '~\.txt[^-]*-\K\d~';
if (preg_match($regex, $mystring, $m)) {
$yourmatch = $m[0];
echo $yourmatch;
}
?> //=> 1
I'm trying to return a certain part of a string. I've looked at substr, but I don't believe it's what I'm looking for.
Using this string:
/text-goes-here/more-text-here/even-more-text-here/possibly-more-here
How can I return everything between the first two // i.e. text-goes-here
Thanks,
$str="/text-goes-here/more-text-here/even-more-text-here/possibly-more-here";
$x=explode('/',$str);
echo $x[1];
print_r($x);// to see all the string split by /
<?php
$String = '/text-goes-here/more-text-here/even-more-text-here/possibly-more-here';
$SplitUrl = explode('/', $String);
# First element
echo $SplitUrl[1]; // text-goes-here
# You can also use array_shift but need twice
$Split = array_shift($SplitUrl);
$Split = array_shift($SplitUrl);
echo $Split; // text-goes-here
?>
The explode methods above certainly work. The reason for matching on the second element is that PHP inserts blank elements in the array whenever it starts with or runs into the delimiter without anything else. Another possible solution is to use regular expressions:
<?php
$str="/text-goes-here/more-text-here/even-more-text-here/possibly-more-here";
preg_match('#/(?P<match>[^/]+)/#', $str, $matches);
echo $matches['match'];
The (?P<match> ... part tells it to match with a named capture group. If you leave out the ?P<match> part, you'll end up with the matching part in $matches[1]. $matches[0] will contain the part with the forward slashes like "/text-goes-here/".
Just use preg_match:
preg_match('#/([^/]+)/#', $string, $match);
$firstSegment = $match[1]; // "text-goes-here"
where
# - start of regex (can be any caracter)
/ - a litteral /
( - beginning of a capturing group
[^/] - anything that isn't a litteral /
+ - one or more (more than one litteral /)
) - end of capturing group
/ - a litteral /
# - end of regex (must match first character of the regex)
I have this code.
<?php
$USClass = "3/312";
$USClass = preg_replace_callback('~[\d.]+/[\d.]+~', function ($matches) {
$parts = explode('/', $matches[0]);
return $parts[1] . ',' . $parts[0];
}, $USClass);
echo $USClass;
?>
It prints 312,3 which is what I wanted.
However, if I give an input like D12/336 then it does not work. I want it to print 336,D12
How can I do it? and What is wrong with my current code which is not handling this Alphanumeric? Is it because I used \d ?
EDIT:
I want it to handle inputs like this as well
148/DIG.111
then the output should be DIG.111,148
Yes \d does only contain digits.
You can try \w instead this is alphanumeric, but additionally it includes also _
To be Unicode you can go for
~[\pL\d.]+/[\pL\d.]+~u
\pL is a Unicode code point with the property "Letter"
The u at the end turn on the UTF-8 mode that is needed to use this feature
See http://www.php.net/manual/en/regexp.reference.unicode.php
Other solution
I think you ar e doing this a bit complicated. It would be simplier if you would make use of capturing groups.
Try this:
$in = "148/DIG.111";
preg_match_all('~([\w.]+)/([\w.]+)~', $in, $matches);
echo $matches[2][0] . ',' . $matches[1][0];
Explanation:
([\w.]+)/([\w.]+)
^^^^^^^^ ^^^^^^^^
Group 1 Group 2
Because of the brackets the matched substring is stored in the array $matches.
See here for more details on preg_match_all
With a simple preg_replace:
$USClass = "148/DIG.111";
$USClass = preg_replace('#(.+?)/(.+)#', "$2,$1", $USClass);
echo $USClass;
output:
DIG.111,148