173

Is there a PHP function that can escape RegEx patterns to prevent them from being applied when used inside another RegEx pattern?

I am looking for something along the lines of the C# Regex.Escape() function.

Top-Master
  • 7,611
  • 5
  • 39
  • 71
vfclists
  • 19,193
  • 21
  • 73
  • 92

2 Answers2

275

preg_quote() is what you are looking for:

Description

string preg_quote ( string $str [, string $delimiter = NULL ] )

preg_quote() takes str and puts a backslash in front of every character that is part of the regular expression syntax. This is useful if you have a run-time string that you need to match in some text and the string may contain special regex characters.

The special regular expression characters are: . \ + * ? [ ^ ] $ ( ) { } = ! < > | : -

Parameters

str

The input string.

delimiter

If the optional delimiter is specified, it will also be escaped. This is useful for escaping the delimiter that is required by the PCRE functions. The / is the most commonly used delimiter.

Importantly, note that if the $delimiter argument is not specified, the delimiter - the character used to enclose your regex, commonly a forward slash (/) - will not be escaped. You will usually want to pass whatever delimiter you are using with your regex as the $delimiter argument.

Example - using preg_match to find occurrences of a given URL surrounded by whitespace:

$url = 'http://stackoverflow.com/questions?sort=newest';

// preg_quote escapes the dot, question mark and equals sign in the URL (by
// default) as well as all the forward slashes (because we pass '/' as the
// $delimiter argument).
$escapedUrl = preg_quote($url, '/');

// We enclose our regex in '/' characters here - the same delimiter we passed
// to preg_quote
$regex = '/\s' . $escapedUrl . '\s/';
// $regex is now:  /\shttp\:\/\/stackoverflow\.com\/questions\?sort\=newest\s/

$haystack = "Bla bla http://stackoverflow.com/questions?sort=newest bla bla";
preg_match($regex, $haystack, $matches);

var_dump($matches);
// array(1) {
//   [0]=>
//   string(48) " http://stackoverflow.com/questions?sort=newest "
// }
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Tom Haigh
  • 57,217
  • 21
  • 114
  • 142
  • 15
    One additional remark to [@TomHaigh](http://stackoverflow.com/a/1531471/89771) answer, if you don't specify the second `$delimiter` argument to `preg_quote()` **[it won't escape any delimiter](http://codepad.org/6mRuajog)**, not even the "default" (or the most common) `/`. – Alix Axel Jun 20 '12 at 03:39
  • 1
    I've added a whole bunch of stuff to this answer - the note brought up by @AlixAxel about the importance of the `$delimiter` argument, the description of that argument from the docs, a clarification for the confused about exactly what it means, and a heavily commented example showing `preg_quote` being used in the simplest case I could come up with where it's actually being used to programatically form a regex and put it into another `preg_*` function (because otherwise, what's the point?). Feel free to rollback if you don't like the change. – Mark Amery Sep 21 '15 at 23:04
  • @AlixAxel The preg_quote() function escapes some delimiters including = : < and >. See my article: https://www.abareplace.com/blog/escape-regexp/ – Peter Kankowski Jan 08 '22 at 11:41
2

It would be much safer to use Prepared Patterns from T-Regx:

$url = 'http://stackoverflow.com/questions?sort=newest';

$pattern = Pattern::inject('\s@\s', [$url]);
                                    // ↑ $url is quoted

then perform normal match:

$haystack = "Bla bla http://stackoverflow.com/questions?sort=newest bla bla";

$matcher = pattern->match($haystack);
foreach ($matcher as $match) {
}

you can even use it with preg_match():

preg_match($pattern, 'foo', $matches);
Danon
  • 2,771
  • 27
  • 37
  • 1
    Can you please explain, why it should be "safer" to pull in another library, if a standard PHP does the job? – Adrian Jan 18 '22 at 07:38
  • Vanilla PHP don't work for all cases. For example string `"\\"` will cause error if it's the last character. – Danon Jan 24 '22 at 13:07
  • This is the second answer I've seen of yours in a day mentioning this library, and I realise now it's because it's your own. SO policy requires that you make any association clear in your answer when recommending your own tools. – Hashim Aziz Mar 21 '23 at 19:02
  • @HashimAziz Thanks for notising, I posted the answer 4 year ago right after I created the lib. I was young and silly, accept my apology. – Danon Mar 22 '23 at 08:22