31

I'm getting this odd error in the preg_match() function:

Warning: preg_match(): Compilation failed: range out of order in character class at offset 54

The line which is causing this is:

preg_match("/<!--GSM\sPER\sNUMBER\s-\s$gsmNumber\s-\sSTART-->(.*)<!--GSM\sPER\sNUMBER\s-\s$gsmNumber\s-\sEND-->/s", $fileData, $matches);

What this regular expression does is parse an HTML file, extracting only the part between:

<!--GSM PER NUMBER - 5550101 - START-->

and:

<!--GSM PER NUMBER - 5550101 - END-->

Do you have a hint about what could be causing this error?

Ariod
  • 5,757
  • 22
  • 73
  • 103
  • check the variable $gsmNumber, that can be the cause. – Bang Dao Aug 11 '10 at 07:05
  • I recommend reading this http://stackoverflow.com/questions/3148240/regex-why-doesnt-01-12-range-work-as-expected - you may have tried to define numeric ranges in a character class. – polygenelubricants Aug 11 '10 at 07:18
  • 1
    I was getting this for [a-Z] (note the capitalization). When it says range it means simply `[a-z]` type regexes. – Jonathon Mar 15 '13 at 17:24

7 Answers7

85

Hi I got the same error and solved it:

  Warning: preg_match(): Compilation failed: range out of order in character class at offset <N>

Research Phase:

.. Range out of order .. So there is a range defined which can't be used.

.. at offset N .. I had a quick look at my regex pattern. Position N was the "-". It's used to define ranges like "a-z" or "0-9" etc.

Solution

I simply escaped the "-".

 \-    

Now it is interpreted as the character "-" and not as range!

krang
  • 851
  • 1
  • 6
  • 3
11

If $gsmNumber contains a square bracket, backslash or various other special characters it might trigger this error. If that's possible, you might want to validate that to make sure it actually is a number before this point.

Edit 2016:

There exists a PHP function that can escape special characters inside regular expressions: preg_quote().

Use it like this:

preg_match(
  '/<!--GSM\sPER\sNUMBER\s-\s' .
  preg_quote($gsmNumber, '/') . '\s-\sSTART-->(.*)<!--GSM\sPER\sNUMBER\s-\s' .
  preg_quote($gsmNumber, '/') . '\s-\sEND-->/s', $fileData, $matches);

Obviously in this case because you've used the same string twice you could assign the quoted version to a variable first and re-use that.

thomasrutter
  • 114,488
  • 30
  • 148
  • 167
  • krang's answer is probably the more relevant answer to this particular issue - assuming $gsmNumber is a number, then the problem will be with the unescaped hyphens. – thomasrutter Sep 09 '18 at 23:46
10

This error is caused for an incorrect range. For example: 9-0 a-Z To correct this, you must change 9-0 to 0-9 and a-Z to a-zA-Z In your case you are not escaping the character "-", and then, preg_match try to parse the regex and fail with an incorrect range. Escape the "-" and it must solve your problem.

Estefano Salazar
  • 419
  • 4
  • 15
6

I was receiving this error with the following sequence:

[/-.]

Simply moving the . to the beginning fixed the problem:

[./-]
N Rohler
  • 4,595
  • 24
  • 20
  • 2
    This is because of the unescaped hyphen. If you place the hyphen last in the character class as in your second example, it doesn't need to be escaped. You could also have solved this problem with: `[/\-.]` ie placing a backslash before the hyphen. – thomasrutter Jul 12 '16 at 00:46
  • `/[^A-Za-z0-9_-\.]/` caused the error on my side. Moving the `\.` "away from the end" (`/[^A-Za-z0-9\._-]/`) worked for me. Thanks! – cottton Apr 06 '22 at 15:00
5

While the other answers are correct, I'm surprised to see that no-one has suggested escaping the variable with preg_quote() before using it in a regex. So if you're looking to match an actual bracket or anything else that means something in regex, that'll be converted to a literal token:

$escaped = preg_quote($gsmNumber);
preg_match( '/<!--GSM\sPER\sNUMBER\s-\s'.$escaped.'\s-\sSTART-->(.*)<!--GSM\sPER\sNUMBER\s-\s'.$escaped.'\s-\sEND-->/s', $fileData, $matches);
rdiz
  • 6,136
  • 1
  • 29
  • 41
0

You probably have people insert mobile numbers including +, -, ( and/or ) characters and just use these as is in your preg_match, so you might want to sanitize the data provided before using it (ie. by stripping these characters out completely).

wimvds
  • 12,790
  • 2
  • 41
  • 42
  • 1
    Instead of stripping those characters you can also escape them, i.e. marking them as literal characters, see http://docs.php.net/preg_quote – VolkerK Aug 11 '10 at 08:10
0

This is a bug in several versions of PHP, as I have just verified for the current 5.3.5 version, as packaged with XAMPP 1.7.4 on Windows XP home edition.

Even some very simple examples exhibit the problem, e.g.,

    $pattern = '/^[\w_-. ]+$/';
    $uid = 'guest';
    if (preg_match($pattern, $uid)) echo 
      ("<style> p { text-decoration:line-through } </style>");

The PHP folks have known about the bug since 1/10/2010. See http://pear.php.net/bugs/bug.php?id=18182. The bug is marked "closed" yet persists.

Page Notes
  • 119
  • 2
  • 5