Запретить пустое содержимое в теге BBCode с атрибутом - PullRequest
4 голосов
/ 16 июня 2019

У меня есть это регулярное выражение:

\[code(?:=(["']?)(.{0,50}?)\1)?\](?!\s*\[\/code\])(.*?)\[\/code\]

Предполагается, что это регулярное выражение поддерживает:

[code]content[/code]
[code=Title]content[/code]
[code="Title"]content[/code]
[code='Title']content[/code]

Пустое содержимое [code][/code] не разрешено, и это сделано благодаря:

(?!\s*\[\/code\])

Также пустое содержимое с заголовком [code=Title][/code] не допускается, и вышеуказанная группа без захвата работает и для этого условия, пока я не вставлю два тега вместе:

[code="title"][/code]
[code][/code]

Как я не могу сопоставить последнее условие с помощью регулярного выражения?
Проблему лучше всего наблюдать здесь: https://regex101.com/r/J1dwJa/2/

Как я понимаю, то, что создает проблемы, является этой частью регулярного выражения:

(["']?)

Я использую квантификатор для поддержки шаблона [code=Title][/code].По крайней мере, я думаю, что это регулярное выражение нуждается в том, что когда оно встречается, ] должно остановиться и не продолжаться.Я пытаюсь, но я не нахожу никакого пути с моим базовым знанием регулярных выражений.

Ответы [ 4 ]

4 голосов
/ 18 июня 2019

Вы должны заботиться о двух вещах:

  1. . будет соответствовать гораздо больше, чем необходимо

  2. Вы не должны совпадать с [/code] в содержательной части при поиске закрытия [/code]

\[code(?>=(["']?)([^][]*)\1)?](?:(?!\s*(\[\/code])).)+(?3)

Смотрите живое демо здесь

2 голосов
/ 20 июня 2019

Движки Regex не сдаются в матче, пока не попробуют все возможности.
В вашем регулярном выражении эта последовательность .{0,50}? будет соответствовать не жадно, от 0 до 50 символов.

В своем примере regex101 вы указали модификатор Dot-all // s, что означает, что ваша точка будет охватывать линии.Так уж получилось, что на следующей строке он может удовлетворить тело (контент), где (?! \ S * [/ code]) проходит.

Вы заметите, что для этого кавычка отбрасывается в обратном направлении, так что ( ["']? ) никогда не совпадает, а \1 - просто пустая строка.Это оставляет дверь открытой для не жадной последовательности, чтобы стать жадной.Это момент GOTCHA.

Обновление

После дальнейшего рассмотрения я твердо верю, что есть только 1 способ
, чтобы удовлетворить все условия, чтобы сделать это регулярное выражение.
Шаги:

  1. Обернуть часть цитаты вокруг атомной группы.
    Это делает эту частьматч непроницаемый для возврата.

  2. Используйте чередование, чтобы различать указанное в кавычках значение или не заключенное в кавычки.
    Сначала поставить цитируемую часть.
    Обратите внимание, что вы вообще не можете использовать отрицательный класс внутри цитируемой части (т. Е. [^\[\]]), поскольку идея цитаты состоит в том, чтобы разрешать такие разделители, как [].
    Эта часть должна пассивно разрешать любыесимвол ..
    Это позволит сопоставить строку, подобную этой
    [code="t][/code]"]hello world[/code]
    , однако невероятная генерация такой строки может быть
    .

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

Группы 2 и 3 содержат значения (одно или другое), просто объедините
их.
Группа 4 содержит содержимое.

(?s)\[code(?>(?:=(?:(["'])(.{0,50}?)\1|([^\]]{0,50})))?)\](?!\s*\[\/code\])(.*?)\[\/code\]

https://regex101.com/r/cO73iA/1

Объяснено

 (?s)                      # Dot-all modifier
 \[code                    # Open bbcode tag
 (?>                       # Atomic group, can't be backtracked into
      (?:
           =
           (?:
                ( ["'] )                  # (1), Quote
                ( .{0,50}? )              # (2), code value
                \1                        # Backref to Quote
             |                          # or,
                ( [^\]]{0,50} )           # (3), Un-quoted code value
           )
      )?
 )
 \]
 (?! \s* \[/code\] )       # Cannot be empty content
 ( .*? )                   # (4), Content, must be some
 \[/code\]                 # Close bbcode tag
0 голосов
/ 18 июня 2019

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

[code='title'][/code]
[code="title"][/code]

Демо 1

Мы также могли бы немного упростить наше выражение до:

\[code(?:=(["']?)(.{0,50}?)\1)?\](.+?)\[\/code\]

Демо 2

0 голосов
/ 16 июня 2019

вы можете использовать следующее обновленное регулярное выражение

\[code(?:=(["']?)([^'"]{0,50}?)\1)?\](?!\s*\[\/code\])(.*?)\[\/code\]

вместо использования .{0,50} используйте [^'"]{0,50}, которые соответствуют любому символу, кроме " или '

проверьте свои совпадения в следующей ссылке

...