preg_replace only substring before defined char - php

I'm trying to replace chars not [A-Z] and before the # inside a string. So this
AreplacehereZ#domain.tld
needs to become:
A***********Z#domain.tld
I tried with:
$string = 'AreplacehereZ#domain.tld';
$pattern = '/(?<!#)[^A-Z#\.]/';
$replacement = '*';
$replace = preg_replace($pattern, $replacement, $tring);
but the result is
'A***********Z#d*****.***'
So I can't find the way how to avoid the replacement of #domain.tld by only using preg_replace().
domain.tld can be anything so I can't use (?<!#domain.tld) in the $pattern var.

You can just assert that from the current position, match [^A-Z], then make sure you can consume any number of characters but still hit the #:
$pattern = '/[^A-Z](?=[^#]*#)/';
Produces:
A***********Z#domain.tld

Related

PHP REGEX find & replace patterns

Trying to construct a regex that will locate a pattern of ANY character followed by double quotes
This regex locates each occurrence properly
(\S"")
Given the example below
$string='"WEINSTEIN","ANTONIA \"TOBY"","STILES","HOOPER \"PETER"","HENDERSON",';
$pattern = '(\S"")';
$replacement = '\\""';
$result=preg_replace($pattern, $replacement, $string);
My result turns out to be
"WEINSTEIN","ANTONIA \"TOB\"","STILES","HOOPER \"PETE\"","HENDERSON"
But I am seeking
"WEINSTEIN","ANTONIA \"TOBY\"","STILES","HOOPER \"PETER\"","HENDERSON"
I understand the replacement is removing/replacing the whole match, but how can I remove all but the first letter rather than completely replacing it?
You can change your pattern to use a positive lookbehind instead so that it doesn't capture the non-space character:
$string='"WEINSTEIN","ANTONIA \"TOBY"","STILES","HOOPER \"PETER"","HENDERSON",';
$pattern = '/(?<=\S)""/';
$replacement = '\\""';
$result=preg_replace($pattern, $replacement, $string);
echo $result;
Output
"WEINSTEIN","ANTONIA \"TOBY\"","STILES","HOOPER \"PETER\"","HENDERSON",
Demo on 3v4l.org

Matching all of a certain character after a Positive Lookbehind

I have been trying to get the regex right for this all morning long and I have hit the wall. In the following string I wan't to match every forward slash which follows .com/<first_word> with the exception of any / after the URL.
$string = "http://example.com/foo/12/jacket Input/Output";
match------------------------^--^
The length of the words between slashes should not matter.
Regex: (?<=.com\/\w)(\/) results:
$string = "http://example.com/foo/12/jacket Input/Output"; // no match
$string = "http://example.com/f/12/jacket Input/Output";
matches--------------------^
Regex: (?<=\/\w)(\/) results:
$string = "http://example.com/foo/20/jacket Input/O/utput"; // misses the /'s in the URL
matches----------------------------------------^
$string = "http://example.com/f/2/jacket Input/O/utput"; // don't want the match between Input/Output
matches--------------------^-^--------------^
Because the lookbehind can have no modifiers and needs to be a zero length assertion I am wondering if I have just tripped down the wrong path and should seek another regex combination.
Is the positive lookbehind the right way to do this? Or am I missing something other than copious amounts of coffee?
NOTE: tagged with PHP because the regex should work in any of the preg_* functions.
If you want to use preg_replace then this regex should work:
$re = '~(?:^.*?\.com/|(?<!^)\G)[^/\h]*\K/~';
$str = "http://example.com/foo/12/jacket Input/Output";
echo preg_replace($re, '|', $str);
//=> http://example.com/foo|12|jacket Input/Output
Thus replacing each / by a | after first / that appears after starting .com.
Negative Lookbehind (?<!^) is needed to avoid replacing a string without starting .com like /foo/bar/baz/abcd.
RegEx Demo
Use \K here along with \G.grab the groups.
^.*?\.com\/\w+\K|\G(\/)\w+\K
See demo.
https://regex101.com/r/aT3kG2/6
$re = "/^.*?\\.com\\/\\w+\\K|\\G(\\/)\\w+\\K/m";
$str = "http://example.com/foo/12/jacket Input/Output";
preg_match_all($re, $str, $matches);
Replace
$re = "/^.*?\\.com\\/\\w+\\K|\\G(\\/)\\w+\\K/m";
$str = "http://example.com/foo/12/jacket Input/Output";
$subst = "|";
$result = preg_replace($re, $subst, $str);
Another \G and \K based idea.
$re = '~(?:^\S+\.com/\w|\G(?!^))\w*+\K/~';
The (: non capture group to set entry point ^\S+\.com/\w or glue matches \G(?!^) to it.
\w*+\K/ possessively matches any amount of word characters until a slash. \K resets match.
See demo at regex101

Regular Expression to replace a bracket with word in front when not preceded by word

I am facing problem with a regular expression.
I have a string like ('A'&'B')
Now I want to convert it to CONCAT('A'&'B') which is simple and I have done using
str_replace("(", "CONCAT(", $subject)
But I want to replace "(" to "CONCAT(" if the string doesn't have prior string "extract_json_value".
So I don't want to replace extract_json_value('A'&'B') to extract_json_valueCONCAT('A'&'B') but it will stay as it is extract_json_value('A'&'B').
You can expand your regex with a negative lookbehind:
(?<!extract_json_value)\(
Here is a regex demo!
You could use strpos to do this.
if (strpos($subject, '(') === 0) {
$subject = str_replace('(', 'CONCAT(', $subject);
}
If your string contains other text you can use preg_replace() and use a word boundary \B for this.
$subject = preg_replace('/\B\(/', 'CONCAT(', $subject);
You can use negative lookbehind in order to match a group not preceded by a string.
First, let's have a regexp matching all strings but those containing "extract_json_value":
(?<!extract_json_value).*
Now, let's use preg_replace
$string = "extract_json_value('A'&'B')";
$pattern = '/^(?<!extract_json_value)(\(.+\))$/';
$replacement = 'CONCAT\1';
echo preg_replace($pattern, $replacement, $string);
// prints out "extract_json_value('A'&'B')"
It works too with
$string = "('A'&'B')";
...
// prints out "CONCAT('A'&'B')"
However, it does not work with
$string = "hello('A'&'B')";
...
// prints out "helloCONCAT('A'&'B')"
So, continue with a preg_replace_callback:
http://php.net/manual/fr/function.preg-replace-callback.php

Some confusion with preg_replace

I am very confused with preg_replace, I have this string and I would like to change ONLY the number before the _
$string = 'string/1_491107.jpg';
$newstring = preg_replace('#([0-9]+)_#', '666', $string);
But then I get "string/666491107.jpg" instead "string/666_491107.jpg"
Thanks
What you're doing here is matching the numbers in the parenthesis as $1 in your replacement. You don't actually say "only the stuff in parenthesises should be replaced".
You could do it like this:
$string = 'string/1_491107.jpg';
$newstring = preg_replace('#[0-9]+_#', '666_', $string);
or you could use a positive lookahead (only match a number sequence followed by an underscore, but don't include the underscore in the match):
$string = 'string/1_491107.jpg';
$newstring = preg_replace('#[0-9]+(?=_)#', '666', $string);
Regex 101 demo
You've got the underscore as part of the text to be replaced; so you also need to include it in the replacement:
$string = 'string/1_491107.jpg';
$newstring = preg_replace('#([0-9]+)_#', '666_', $string);

How to use preg_replace to replace everything within slashes? (Only every other match is replaced)

I am new to regular expressions, and I've been trying to use it with an url, but I can't get it to work.
I have a string that is:
/plugins/plugins/plugins/plugins/plugins/plugins/
and I would like to replace all letters to the string "{char}" so that the string end up being:
/{char}/{char}/{char}/{char}/{char}/{char}/
I've tried this:
<?php
$pattern = '#(/)([a-z\_]+)(/)#';
$replacement = '$1{char}$3';
$string = '/plugins/plugins/plugins/plugins/plugins/plugins/';
echo preg_replace($pattern, $replacement, $string);
?>
But this code is resulting in this:
/{char}/plugins/{char}/plugins/{char}/plugins/
What am I doing wrong?
The problem is your regex is matching /plugins/ - matching slashes at both the front and the end. Each letter is only matched by the regex once, so if a slash is matched at the end of one word it can't also be counted as the start of another. Hence, it's only matching every other one.
Try this instead:
<?php
$pattern = '#(/)([a-z\_]+)(?=/)#';
$replacement = '$1{char}';
$string = '/plugins/plugins/plugins/plugins/plugins/plugins/';
echo preg_replace($pattern, $replacement, $string);
?>
It works by using lookahead, instead of actually matching the final slash (and "consuming" it) it just checks to make sure it's there.

Categories