"line break" is ill-defined:
-- Windows uses CR+LF (\r\n)
-- Linux LF (\n)
-- OSX CR (\r)
Little-known special character:
\R in preg_* matches all three.
preg_match( '/^\R$/', "match\nany\\n\rline\r\nending\r" ); // match any line endings
Обратная косая черта («\») имеет несколько назначений. Прежде всего, если она предшествует не буквенно-цифровому символу, она снимает с него специальное значение, которое он мог иметь. Применение обратной косой черты как экранирующего символа допустимо как в символьном классе, так и вне него.
Например, если нужно задать соответствие символу «*», в шаблоне указывают «\*». Это предотвратит трактование последующего символа как метасимвола с особым значением. В любых случаях безопасно экранировать не буквенно-цифровые символы символом обратной косой черты «\», если нужно убедиться, что они означают в шаблоне самих себя. В частном случае для сопоставления с самим символом обратной косой черты, используйте запись «\\».
Замечание:
PHP-строки, заключённые в одинарные и двойные кавычки, по-особому интерпретируют обратную косую черту. Таким образом, если необходимо сопоставить \ с регулярным выражением \\, в PHP-коде нужно использовать "\\\\" или '\\\\'.
Если указан модификатор PCRE_EXTENDED, пробельные символы в шаблоне (вне описания символьного класса) игнорируются. Также игнорируется часть строки, находящаяся между символом «#» (опять же, не участвующем в описании символьного класса) и следующим символом перевода строки. В этой ситуации обратный слеш можно применять как экранирующий символ для указания вхождений пробельных символов или символа «#» в шаблоне.
Второе применение обратного слеша заключается в том, что он позволяет использовать непечатные символы в видимой форме в описании шаблона. При том что в PCRE нет ограничений на использование непечатных символов (исключая бинарный ноль, который интерпретируется как конец шаблона), при редактировании программного кода в каком-либо текстовом редакторе гораздо удобнее использовать следующие комбинации, чем реальные символы, которые они представляют:
Если быть более точным, комбинация «\cx
» интерпретируется
следующим образом: если «x
» — символ нижнего регистра,
он преобразовывается в верхний регистр.
После этого шестой бит символа (шестнадцатеричный код 40) инвертируется.
Таким образом, «\cz
» интерпретируется как шестнадцатеричное
значение 1A, в то время как «\c{
» получает шестнадцатеричное
значение 3B, а «\c;
» — 7B.
После «\x
» считываются ещё две шестнадцатеричные цифры
(они могут быть записаны в нижнем или верхнем регистре).
В режиме UTF-8, разрешается использование
«\x{...}
», где содержимое скобок является строкой
из шестнадцатеричных цифр. Она интерпретируется как символ UTF-8 character с кодом,
совпадающим с данным шестнадцатеричным числом.
Исходная шестнадцатеричная экранирующая последовательность,
\xhh
, совпадает с двухбайтным UTF-8 символом, если его значение
превышает 127.
После «\0
» считываются две восьмеричные цифры.
Если в записи менее двух цифр, будут использованы
все фактически присутствующие цифры. Таким образом, последовательность
«\0\x\07
» будет интерпретирована как два бинарных нуля,
за которыми следует символ оповещения (звонок). Если вы используете
представление числа в восьмеричном коде, убедитесь, что за
начальным нулём следуют две значащие цифры.
Обработка обратного слеша, за которым следует ненулевая цифра, несколько сложнее. Вне символьного класса PCRE воспринимает обратный слеш и следующие за ним цифры как десятичное число. Если полученное значение меньше десяти, либо если шаблон содержит по меньшей мере такое же количество предшествующих текущей позиции подмасок, вся конструкция интерпретируется как ссылка на подмаску. Более детальное описание будет приведено ниже при обсуждении механизма работы подмасок.
Внутри символьного класса, либо если полученное значение больше 9 и соответствующее количество предшествующих подмасок отсутствует, PCRE считывает до трёх восьмеричных цифр, следующих за обратным слешем, и генерирует один байт из последних 8-ми значащих битов полученного значения. Все последующие цифры обозначают себя же. Например:
Следует помнить, что восьмеричные значения, превышающие 100, следует писать без лидирующего нуля, так как читается не более трёх восьмеричных цифр.
Все последовательности, определяющие однобайтное значение, могут встречаться
как внутри, так и вне символьных классов. Кроме того, внутри символьного класса
запись «\b
» интерпретируется как символ возврата
(«backspace», шестнадцатеричный код 08). Вне символьного класса она имеет
другое значение (какое именно, описано ниже).
Третье использование обратного слеша — указание общего типа символов:
Каждая пара таких специальных последовательностей делит полное множество всех символов на два непересекающихся множества. Любой символ соответствует одному и только одному множеству из пары.
Следующие символы считаются как «пробельные»: HT (9), LF (10), FF (12), CR (13), и пробел (32). Тем не менее, если идёт локале-зависимый поиск, и произойдёт совпадение с символами в диапазоне 128-255, они также будут восприняты как пробельные, например NBSP (A0).
Символ, образующий «слово» — это произвольная цифра, буква или символ подчёркивания,
проще говоря, любой символ, который может являться частью
«слова» в Perl. Определение букв и цифр управляется
символьными таблицами, с которыми была собрана PCRE. И, как следствие, эти наборы
могут отличаться в различных локализированных дистрибутивах.
Например, в локали «fr» (Франция) ряд символов с кодом выше 128 применяют
для записи ударных символов и поэтому они соответствуют маске \w
.
Описанные выше типы символов могут применяться как внутри, так и вне символьных классов, и соответствуют одному символу данного типа. Если текущая точка сравнения находится в конце строки, ни один из них не сможет совпасть, так как нет символа, с которым могло бы произойти совпадение.
Четвёртое использование обратного слеша — определение некоторых формальных утверждений, описывающих условия касательно месторасположения особых позиций в строке и совершенно не затрагивающих сами символы. Использование подмасок как более сложных формальных утверждений описано ниже. Такими управляющими последовательностями являются:
Описанные выше последовательности не могут встречаться в символьных классах
(исключая комбинацию «\b
», которая внутри класса означает
символ возврата «backspace»).
Границей слова считается такая позиция в строке, в которой из текущего и
предыдущего символа только один соответствует \w
или
\W
(т.е. один из них соответствует \w
,
а другой \W
). Начало или конец строки также соответствуют
границе слова Если первый или, соответственно, последний символ совпадает
с \w
.
Специальные последовательности \A
, \Z
и
\z
отличаются от общеупотребляемых метасимволов начала строки
(«^») и конца строки («$»), описанных в разделе «Якоря»,
тем, что они всегда совпадают либо в самом начале либо в самом конце строки.
На них никак не влияют опции
PCRE_MULTILINE и
PCRE_DOLLAR_ENDONLY.
Разница между \Z
и \z
в том,
что \Z
соответствует позиции перед последним символом
Если последний символ — перевод строки, кроме самого конца строки.
В то время, как \z
соответствует исключительно концу данных.
Утверждение \G
является истинным только в том случае,
если текущая проверяемая позиция находится в начале совпадения, указанного
параметром offset
функции preg_match().
Она отличается от \A
при ненулевом значении параметра
offset
.
\Q
и \E
могут быть использованы для
игнорирования метасимволов регулярных выражений в шаблоне. Например:
\w+\Q.$.\E$
совпадёт с один или более символов,
составляющих «слово»,за которыми следуют символы .$.
и якорь в конце строки. Обратите внимание, что это не меняет поведения
разделителей; например, шаблон #\Q#\E#$
некорректен, потому что второй #
отмечает конец шаблона,
а \E#
интерпретируется как недопустимые модификаторы.
Последовательность \K
может быть использована для сброса
начала совпадения. Например, шаблон
foo\Kbar
совпадёт с «foobar», но сообщит о том, что
совпал только с «bar». Использование
\K
не мешает установке подмасок. Например, если шаблон
(foo)\Kbar
совпадёт со строкой «foobar», первой подмаской
всё равно будет являться «foo».
"line break" is ill-defined:
-- Windows uses CR+LF (\r\n)
-- Linux LF (\n)
-- OSX CR (\r)
Little-known special character:
\R in preg_* matches all three.
preg_match( '/^\R$/', "match\nany\\n\rline\r\nending\r" ); // match any line endings
Significantly updated version (with new $pat4 utilising \R properly, its results and comments):
Note that there are (sometimes difficult to grasp at first glance) nuances of meaning and application of escape sequences like \r, \R and \v - none of them is perfect in all situations, but they are quite useful nevertheless. Some official PCRE control options and their changes come in handy too - unfortunately neither (*ANYCRLF), (*ANY) nor (*CRLF) is documented here on php.net at the moment (although they seem to be available for over 10 years and 5 months now), but they are described on Wikipedia ("Newline/linebreak options" at https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions) and official PCRE library site ("Newline convention" at http://www.pcre.org/original/doc/html/pcresyntax.html#SEC17) pretty well. The functionality of \R appears somehow disappointing (with default configuration of compile time option) according to php.net as well as official description ("Newline sequences" at https://www.pcre.org/original/doc/html/pcrepattern.html#newlineseq) when used improperly.
A hint for those of you who are trying to fight off (or work around at least) the problem of matching a pattern correctly at the end ($) of any line in multiple lines mode (/m).
<?php
// Various OS-es have various end line (a.k.a line break) chars:
// - Windows uses CR+LF (\r\n);
// - Linux LF (\n);
// - OSX CR (\r).
// And that's why single dollar meta assertion ($) sometimes fails with multiline modifier (/m) mode - possible bug in PHP 5.3.8 or just a "feature"(?).
$str="ABC ABC\n\n123 123\r\ndef def\rnop nop\r\n890 890\nQRS QRS\r\r~-_ ~-_";
// C 3 p 0 _
$pat1='/\w$/mi'; // This works excellent in JavaScript (Firefox 7.0.1+)
$pat2='/\w\r?$/mi'; // Slightly better
$pat3='/\w\R?$/mi'; // Somehow disappointing according to php.net and pcre.org when used improperly
$pat4='/\w(?=\R)/i'; // Much better with allowed lookahead assertion (just to detect without capture) without multiline (/m) mode; note that with alternative for end of string ((?=\R|$)) it would grab all 7 elements as expected
$pat5='/\w\v?$/mi';
$pat6='/(*ANYCRLF)\w$/mi'; // Excellent but undocumented on php.net at the moment (described on pcre.org and en.wikipedia.org)
$n=preg_match_all($pat1, $str, $m1);
$o=preg_match_all($pat2, $str, $m2);
$p=preg_match_all($pat3, $str, $m3);
$r=preg_match_all($pat4, $str, $m4);
$s=preg_match_all($pat5, $str, $m5);
$t=preg_match_all($pat6, $str, $m6);
echo $str."\n1 !!! $pat1 ($n): ".print_r($m1[0], true)
."\n2 !!! $pat2 ($o): ".print_r($m2[0], true)
."\n3 !!! $pat3 ($p): ".print_r($m3[0], true)
."\n4 !!! $pat4 ($r): ".print_r($m4[0], true)
."\n5 !!! $pat5 ($s): ".print_r($m5[0], true)
."\n6 !!! $pat6 ($t): ".print_r($m6[0], true);
// Note the difference among the three very helpful escape sequences in $pat2 (\r), $pat3 and $pat4 (\R), $pat5 (\v) and altered newline option in $pat6 ((*ANYCRLF)) - for some applications at least.
/* The code above results in the following output:
ABC ABC
123 123
def def
nop nop
890 890
QRS QRS
~-_ ~-_
1 !!! /\w$/mi (3): Array
(
[0] => C
[1] => 0
[2] => _
)
2 !!! /\w\r?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)
3 !!! /\w\R?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)
4 !!! /\w(?=\R)/i (6): Array
(
[0] => C
[1] => 3
[2] => f
[3] => p
[4] => 0
[5] => S
)
5 !!! /\w\v?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)
6 !!! /(*ANYCRLF)\w$/mi (7): Array
(
[0] => C
[1] => 3
[2] => f
[3] => p
[4] => 0
[5] => S
[6] => _
)
*/
?>
Unfortunately, I haven't got any access to a server with the latest PHP version - my local PHP is 5.3.8 and my public host's PHP is version 5.2.17.
A non breaking space is not considered as a space and cannot be caught by \s.
it can be found with :
- [\xc2\xa0] in utf-8
- \x{00a0} in unicode
As \v matches both single char line ends (CR, LF) and double char (CR+LF, LF+CR), it is not a fixed length atom (eg. is not allowed in lookbehind assertions).
Note that there are (sometimes difficult to grasp at first glance) nuances of meaning and application of escape sequences like \r, \R and \v - none of them is perfect in all situations, but they are quite useful nevertheless. Some official PCRE control options and their changes come in handy too - unfortunately neither (*ANYCRLF), (*ANY) nor (*CRLF) is documented here on php.net at the moment (although they seem to be available for over 10 years and 5 months now), but they are described on Wikipedia ("Newline/linebreak options" at https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions) and official PCRE library site ("Newline convention" at http://www.pcre.org/original/doc/html/pcresyntax.html#SEC17) pretty well. The functionality of \R appears somehow disappointing (with default configuration of compile time option) according to php.net as well as official description ("Newline sequences" at https://www.pcre.org/original/doc/html/pcrepattern.html#newlineseq).
A hint for those of you who are trying to fight off (or work around at least) the problem of matching a pattern correctly at the end ($) of any line in multiple lines mode (/m).
<?php
// Various OS-es have various end line (a.k.a line break) chars:
// - Windows uses CR+LF (\r\n);
// - Linux LF (\n);
// - OSX CR (\r).
// And that's why single dollar meta assertion ($) sometimes fails with multiline modifier (/m) mode - possible bug in PHP 5.3.8 or just a "feature"(?).
$str="ABC ABC\n\n123 123\r\ndef def\rnop nop\r\n890 890\nQRS QRS\r\r~-_ ~-_";
// C 3 p 0 _
$pat1='/\w$/mi'; // This works excellent in JavaScript (Firefox 7.0.1+)
$pat2='/\w\r?$/mi';
$pat3='/\w\R?$/mi'; // Somehow disappointing according to php.net and pcre.org
$pat4='/\w\v?$/mi';
$pat5='/(*ANYCRLF)\w$/mi'; // Excellent but undocumented on php.net at the moment
$n=preg_match_all($pat1, $str, $m1);
$o=preg_match_all($pat2, $str, $m2);
$p=preg_match_all($pat3, $str, $m3);
$r=preg_match_all($pat4, $str, $m4);
$s=preg_match_all($pat5, $str, $m5);
echo $str."\n1 !!! $pat1 ($n): ".print_r($m1[0], true)
."\n2 !!! $pat2 ($o): ".print_r($m2[0], true)
."\n3 !!! $pat3 ($p): ".print_r($m3[0], true)
."\n4 !!! $pat4 ($r): ".print_r($m4[0], true)
."\n5 !!! $pat5 ($s): ".print_r($m5[0], true);
// Note the difference among the three very helpful escape sequences in $pat2 (\r), $pat3 (\R), $pat4 (\v) and altered newline option in $pat5 ((*ANYCRLF)) - for some applications at least.
/* The code above results in the following output:
ABC ABC
123 123
def def
nop nop
890 890
QRS QRS
~-_ ~-_
1 !!! /\w$/mi (3): Array
(
[0] => C
[1] => 0
[2] => _
)
2 !!! /\w\r?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)
3 !!! /\w\R?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)
4 !!! /\w\v?$/mi (5): Array
(
[0] => C
[1] => 3
[2] => p
[3] => 0
[4] => _
)
5 !!! /(*ANYCRLF)\w$/mi (7): Array
(
[0] => C
[1] => 3
[2] => f
[3] => p
[4] => 0
[5] => S
[6] => _
)
*/
?>
Unfortunately, I haven't got any access to a server with the latest PHP version - my local PHP is 5.3.8 and my public host's PHP is version 5.2.17.