How to append or replace trailing question marks using preg_replace? - php

I want to enforce single question mark at the and of the string. In JavaScript it works perfectly:
var re = /[?7!1]*$/;
document.write('lolwut'.replace(re, '?'));
document.write('lolwut?'.replace(re, '?'));
document.write('lolwut??'.replace(re, '?'));
document.write('lolwut???'.replace(re, '?'));
document.write('lolwut???!!!11'.replace(re, '?'));
All of returned values equals "lolwut?"
PHP variant doesnt work that smooth:
$re = '/[?7!1]*$/';
echo preg_replace($re, '?', 'lolwut') . "\n";
echo preg_replace($re, '?', 'lolwut?') . "\n";
echo preg_replace($re, '?', 'lolwut??') . "\n";
echo preg_replace($re, '?', 'lolwut???') . "\n";
echo preg_replace($re, '?', 'lolwut???!!!11') . "\n";
output is:
lolwut?
lolwut??
lolwut??
lolwut??
lolwut??
What i'm doing wrong here?
Update:
$ (Dollar) Assert end of string
An assertion is a test on the characters following or preceding the current matching point that does not actually consume any characters.
is my confusion here, along with implicit global flag of preg_replace, thanks to salathe for providing a clue. (you guys should vote his answer up, really)

Checkout rtrim() - http://php.net/manual/en/function.rtrim.php
echo rtrim('lolwut','?7!1').'?'; // lolwut?
echo rtrim('lolwut?','?7!1').'?'; // lolwut?
echo rtrim('lolwut??','?7!1').'?'; // lolwut?
echo rtrim('lolwut???!!!11','?7!1').'?'; // lolwut?
echo rtrim('lolwut1??!7!11','?7!1').'?'; // lolwut?
rtrim will Strip whitespace (or other characters) from the end of a string
The second argument:
You can also specify the characters you want to strip, by means of the charlist parameter. Simply list all characters that you want to be stripped. With .. you can specify a range of characters.

Just to answer the question asked ("What i'm doing wrong here?"), you're being confused about what precisely the regular expression matches. With the strings presented, bar the first one, the regex actually matches twice which is why you get two question marks (two matches, two replacements). The root of this behaviour is a mixture of the quantifier (* allows matching nothing) and the end-anchor ($ matches the end of the string).
For lolwut???!!!11:
The regex first matches ???!!!11 which is what you expect
Giving the string a new value of lulwut?
Then it also matches at the point right at the end of the new string
Leading to a final replaced value of lulwut??
If you wanted to continue using the same regex with preg_replace then simply restrict it to one replacement by providing a value of 1 to the fourth ($limit) argument:
preg_replace('/[?7!1]*$/', '?', 'lolwut???!!!111', 1);
// limit to only one replacement ------------------^
As for a better solution, as the others have said, use rtrim.

You should use the trim function:
echo trim('lolwut???!!!11', '?7!1');
output is:
lolwut

Related

How to match alphanumeric and symbols using PHP?

I'm working with text content in UTF8 encoding stored in variable $title.
Using preg_replace, how do I append an extra space if the $title string is ending with:
upper/lower case character
digit
symbol, eg. ? or !
This should do the trick:
preg_replace('/^(.*[\w?!])$/', "$1 ", $string);
In essence what it does is if the string ends in one of your unwanted characters it appends a single space.
If the string doesn't match the pattern, then preg_replace() returns the original string - so you're still good.
If you need to expand your list of unwanted endings you can just add them into the character block [\w?!]
Using a positive lookbehind before the end of the line.
And replace with a space.
$title = preg_replace('/(?<=[A-Za-z0-9?!])$/',' ', $title);
Try it here
You may want to try this Pattern Matching below to see if that does it for you.
<?php
// THE REGEX BELOW MATCHES THE ENDING LOWER & UPPER-CASED CHARACTERS, DIGITS
// AND SYMBOLS LIKE "?" AND "!" AND EVEN A DOT "."
// HOWEVER YOU CAN IMPROVISE ON YOUR OWN
$rxPattern = "#([\!\?a-zA-Z0-9\.])$#";
$title = "What is your name?";
var_dump($title);
// AND HERE, YOU APPEND A SINGLE SPACE AFTER THE MATCHED STRING
$title = preg_replace($rxPattern, "$1 ", $title);
var_dump($title);
// THE FIRST var_dump($title) PRODUCES:
// 'What is your name?' (length=18)
// AND THE SECOND var_dump($title) PRODUCES
// 'What is your name? ' (length=19) <== NOTICE THE LENGTH FROM ADDED SPACE.
You may test it out HERE.
Cheers...
You need
$title=preg_replace("/.*[\w?!]$/", "\\0 ", $title);

Add + before word, see all between quotes as one word

I have a question. I need to add a + before every word and see all between quotes as one word.
A have this code
preg_replace("/\w+/", '+\0', $string);
which results in this
+test +demo "+bla +bla2"
But I need
+test +demo +"bla bla2"
Can someone help me :)
And is it possible to not add a + if there is already one? So you don't get ++test
Thanks!
Maybe you can use this regex:
$string = '+test demo between "double quotes" and between \'single quotes\' test';
$result = preg_replace('/\b(?<!\+)\w+|["|\'].+?["|\']/', '+$0', $string);
var_dump($result);
// which will result in:
string '+test +demo +between +"double quotes" +and +between +'single quotes' +test' (length=74)
I've used a 'negative lookbehind' to check for the '+'.
Regex lookahead, lookbehind and atomic groups
I can't test this but could you try it and let me know how it goes?
First the regex: choose from either, a series of letters which may or may not be preceded by a '+', or, a quotation, followed by any number of letters or spaces, which may be preceded by a '+' followed by a quotation.
I would hope this matches all your examples.
We then get all the matches of the regex in your string, store them in the variable "$matches" which is an array. We then loop through this array testing if there is a '+' as the first character. If there is, do nothing, otherwise add one.
We then implode the array into a string, separating the elements by a space.
Note: I believe $matches in created when given as a parameter to preg_match.
$regex = '/[((\+)?[a-zA-z]+)(\"(\+)?[a-zA-Z ]+\")]/';
preg_match($regex, $string, $matches);
foreach($matches as $match)
{
if(substr($match, 0, 1) != "+") $match = "+" + $match;
}
$result = implode($matches, " ");

PHP Remove Brackets on outside of string

I need to remove the outside brackets of a string, but not the inside ones.
For example:
"(-58)" -> "-58"
"('test')" -> "'test'"
"('st())" -> "st()"
" (hd)h(l() ) " -> "hd)h(l() " --> removed all chars up to the bracket
Hopefully you can see what I mean.
I know how to remove all the brackets inside a string, but am not sure how to remove just the first and last ones. I also need it to remove all the chars UP TO the bracket, as there could be a space before/after the bracket which I do not want.
Any help would be greatly appreciated.
One way is to use preg_replace(). This regex replaces leading and trailing brackets (only one) and spaces according to your examples:
/(^\s*\()|(\)\s*$)/
You can use it like this:
$string = ' (hd)h(l() ) ';
$pattern = '/(^\s*\()|(\)\s*$)/';
$replacement = '';
echo preg_replace($pattern, $replacement, $string); // Output: "hd)h(l() "
Using php's trim() may lead to unexpected over-matching. Consider the following implementation:
$strings=[
"(-58)", // -> "-58"
"('test')", // -> "'test'"
"('st())", // -> "st()"
" (hd)h(l() ) ", // -> "hd)h(l() " --> removed all chars up to the bracket
" ((2x parentheses))" // -> assumed to be "(2x parentheses)"
];
foreach($strings as $s){
// use double trim() to strip leading/trailing spaces, then parentheses
var_export(trim(trim($s,' '),'()'));
echo "\n";
}
Output:
'-58'
'\'test\''
'\'st'
'hd)h(l() '
'2x parentheses' // notice this string had two sets of parentheses removed!
Although several string manipulating functions could be used to generate the desired string, using regex is a more direct approach.
Given the following input data:
(-58)
('test')
('st())
(hd)h(l() )
((2x parentheses))
Gergo's pattern will accurately replace the desired characters with and empty string in 261 steps.
I would like to suggest a more efficient and brief pattern with equivalent accuracy given the OP's sample strings.
/^ ?\(|\) ?$/ #142 steps
Demo Link
Enhancements:
Capture groups are not needed for the pipe to separate the two alternatives. (improves efficiency and brevity)
Replace white-space character \s with literal space character. (improves brevity *and potentially accuracy)
Reduce quantifier on spaces from zero or more to zero or one. (more literal to sample data)
You can use trim() function as shown below
$a="(-58)";
$str=trim($a,"()");
echo $str;

PHP replacement is empty, or not replaced

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);

Regex Group Replace

So I'm trying to do a string replace and something is happening that I wouldn't expect to happen and wanted to see if someone could shed some light on it.
I'm trying to do a regex replace where I replace '| ' if it is present. I'm using a group matching and the question mark to get it done, but for some reason it's replacing just spaces as well.
$str = 'x x';
$str = preg_replace('/(| )?/','',$str);
echo $str; // Echoes out 'xx' whereas it should return 'x x'
But when I replace a space with a carret I get:
$str = 'x^x';
$str = preg_replace('/(|^)?/','',$str);
echo $str; // Echoes out 'x^x' as expected
Is there some special thing with spaces that I'm not remembering? Or should this just work?
I tried the following:
$str = preg_replace('/(|\s)?/','',$str);
$str = preg_replace('/(|[ ])?/','',$str);
And both of them are also giving the inaccurate results. Thoughts?
Oh, didn't know you were waiting for me xD
As per comment, you should escape the pipe with a backslash: \|.
The | (pipe) is a special character in regex and means 'or', so that your regex were matching either 'nothing' or 'space' in the first one and either nothing or caret ^ in the second one.

Categories