Что означает "[^] []" регулярное выражение?

Я нашел его в следующем регулярном выражении:

\[(?:[^][]|(?R))*\]

Он соответствует квадратным скобкам (с их содержимым) вместе с вложенными квадратными скобками.

Ответ 1

[^][] - это класс символов, который означает все символы, кроме [ и ].

Вы можете избежать экранирования специальных символов [ и ], поскольку это не является двусмысленным для PCRE, механизма регулярных выражений, используемого в preg_.

Так как [^] неверно в PCRE, единственный способ для синтаксического анализа регулярных выражений состоит в том, что ] находится внутри класса символов, который будет закрыт позже. То же самое с [. Он не может повторно открыть класс символов (кроме символьного класса POSIX [:alnum:]) внутри класса символов. Тогда последний ] понятен; это конец класса символов. Однако a [ вне класса символов должен быть экранирован, так как он анализируется как начало класса символов.

Таким же образом вы можете написать []] или [[] или [^[] без экранирования [ или ] в классе символов.

Вы можете использовать этот синтаксис с несколькими регулярными выражениями: PCRE (PHP, R), Perl, Python, Java,.NET, GO, awk, Tcl (если вы разделите свой рисунок фигурными скобками, спасибо Donal Fellows)...

Но не с: Ruby, JavaScript (кроме IE < 9),...

Как отмечал m.buettner, [^]] не является двусмысленным, поскольку ] является символом first, [^a]] рассматривается как все, что не является a, за которым следует ]. Чтобы иметь a и ], вы должны написать: [^a\]] или [^]a]

В частном случае JavaScript спецификация позволяет [] как токен регулярного выражения, который никогда не совпадает (другими словами, [] всегда терпит неудачу) и [^] как регулярное выражение, которое соответствует любому символу. Тогда [^]] рассматривается как любой символ, за которым следует a ]. Фактическая реализация меняется, но современный браузер обычно придерживается определения в спецификации.

Сведения о шаблоне:

\[          # literal [
(?:         # open a non capturing group
    [^][]   # a character that is not a ] or a [
  |         # OR
    (?R)    # the whole pattern (here is the recursion)
)*          # repeat zero or more time
\]          # a literal ]

В вашем примере шаблона вам не нужно избегать последнего ]

Но вы можете сделать то же самое с этим шаблоном, немного оптимизированным, и более полезную причину можно использовать повторно как подшаблон (?-1)): (\[(?:[^][]+|(?-1))*+])

(                     # open the capturing group
    \[                # a literal [
        (?:           # open a non-capturing group
            [^][]+    # all characters but ] or [ one or more time
          |           # OR
            (?-1)     # the last opened capturing group (recursion)
                      # (the capture group where you are)
        )*+           # repeat the group zero or more time (possessive)
    ]                 # literal ] (no need to escape)
)                     # close the capturing group

или лучше: (\[[^][]*(?:(?-1)[^][]*)*+]), что позволяет избежать затрат на чередование.