Как этот шаблон соответствует дефису без побега?

После перебора в regex101 в течение нескольких минут, я понял, что ] не нужно экранировать, если он немедленно обращается к [.

В regex101 шаблон []-a-z] описывается как

/[]-a-z]/ []-a-z] match a single character present in the list below ]-a a single character in the range between ] and a (case sensitive) -z a single character in the list -z literally (case sensitive)

Но я всегда думал, что если - нужно подбирать буквально, не избегая его, он должен либо идти в начале, либо в конце.

Затем почему мой шаблон не распознан как ошибка? Почему -z буквально соответствует одному символу в списке -z?

Ответ 1

Позвольте сломать его:

[]-a-z]
 ^^ ^
 || +---- 3
 |+------ 2
 +------- 1

1 является литералом ], поскольку он появляется в начале шаблона, а [] является недопустимым символьным классом в PCRE.

Таким образом, 2 дефис является вторым символом в классе и вводит диапазон между ] и a.

Следующий дефис 3 обрабатывается буквально, потому что предыдущий токен a - это конец предыдущего диапазона. Другой диапазон не может быть введен в этот момент. В PCRE a - обрабатывается буквально, если он находится в месте, где диапазон не может быть введен или если он сбежал. Мы обычно размещаем буквальные дефисы в начале или в конце диапазона, чтобы сделать это очевидным, но это не требуется.

Тогда z - простой литерал.

PCRE следует за синтаксисом Perl. Это документировано следующим образом:

О ]:

A ] обычно является либо концом класса символов POSIX (см. ниже приведенные ниже классы символов POSIX), либо он сигнализирует о конце класса символов в квадратных скобках. Если вы хотите включить ] в набор символов, вы, скорее всего, избежите его.
Однако, если ] является первым символом (или вторым, если первый символ является символом каретки) символьного символьного класса, он не обозначает конец класса (поскольку вы не можете пустой класс) и считается частью набора символов, которые могут быть сопоставлены без экранирования.

О дефисах:

Если дефис в символьном классе не может синтаксически быть частью диапазона, например, потому что он является первым или последним символом класса символов, или если он сразу следует за диапазон, дефис не является особым, и поэтому считается символом, который должен соответствовать буквально. Если вы хотите, чтобы дефис в вашем наборе символов был сопоставлен, а его позиция в классе такова, что его можно считать частью диапазона, вы должны избежать этого дефиса с обратным слэшем.

Обратите внимание, что это относится к синтаксису Perl. Другие вкусы могут иметь другое поведение. Например, [] является допустимым (пустым) символьным классом в JavaScript, который ничего не может сопоставить.

Ловушка заключается в том, что в зависимости от параметров PCRE также может интерпретировать это в JS-режиме (там есть несколько флагов совместимости JS). Из PCRE2 docs:

Открывающая квадратная скобка вводит класс символов, заканчивающийся закрывающей квадратной скобкой. Закрывающая квадратная скобка сама по себе не является особенной по умолчанию. Если в качестве члена класса требуется закрывающая квадратная скобка, она должна быть первым символом данных в классе (после начального обводки, если он есть) или экранированным обратным слэшем. Это означает, что по умолчанию пустой класс не может быть определен. Однако, если параметр PCRE2_ALLOW_EMPTY_CLASS установлен, закрывающая квадратная скобка в начале заканчивает (пустой) класс.

Зарегистрированное поведение PCRE в отношении дефиса, неудивительно, соответствует поведению Perl:

Символ минус (дефис) может использоваться для указания диапазона символов в классе символов. Например, [d-m] соответствует любой букве между d и m включительно. Если в классе требуется минус-символ, он должен быть экранирован с помощью обратного слэша или появится в позиции, где его нельзя интерпретировать как указание диапазона, как правило, в качестве первого или последнего символа в классе, или сразу после диапазона. Например, [b-d-z] соответствует буквам в диапазоне от b до d, символу дефиса или z.

Ответ 2

Информация о Regex:

Дефисы в других позициях в классах символов , где они не могут сформировать диапазон может быть интерпретирован как литералы или как ошибки. Реджикс-ароматизаторы совершенно несовместимо с этим.

Итак, здесь - не может сформировать диапазон, поскольку предыдущий токен представляет собой диапазон в отличие от символа и, следовательно, он интерпретируется как литерал -

Ответ 3

Регулярное выражение не прерывается, потому что - означает диапазон здесь, от ] до a. ] не обязательно должен быть экранирован в исходной позиции внутри класса символов, поэтому здесь он рассматривается как литерал. Класс символов действителен, поскольку ] имеет код 93 ASCII, а a имеет код 97 в таблице ASCII.

EDIT:

Существует одна вещь, которая универсальна в отношении регулярных выражений: они анализируются слева направо. Таким образом, диапазон формируется с использованием первых символов вокруг первого дефиса. Второй дефис идет сразу после символа конца диапазона, и он не может использоваться в качестве символа начального диапазона, поскольку он "занят". Таким образом, механизм регулярных выражений не может не анализировать второй дефис как литерал

См. Ссылка PCRE:

Символ минус (дефис) может использоваться для указания диапазона ха-        в классе символов. Например, [d-m] соответствует любой букве        между d и m, включительно. Если в        класса, он должен быть экранирован с обратной косой чертой или находиться в позиции        где его нельзя интерпретировать как указание диапазона, как правило, как        первый или последний символ в классе или сразу после диапазона. Для        Например, [b-d-z] соответствует буквам в диапазоне от b до d,        ter или z.

Ответ 4

он не даст никакой ошибки. "-" используется для диапазона между указанным символом. Для этого "[] -a-z]" соответствует символу между "] и" а ", а также" от a до z ". для более подробного пояснения смотрите следующий пример:

  import java.util.regex.*;
    import java.lang.*;
    import java.io.*;

    /* Name of the class has to be "Main" only if the class is public. */
    class Regex_Ex
    {
    public static void main (String[] args) throws java.lang.Exception
    {
    String l = "raj kumar kash]an";
    Pattern p = Pattern.compile("[]-a-z]");
    Matcher m = p.matcher(l);
    while(m.find()){
    System.out.println(m.group());
    }
    }
    }