Как найти текст в скобках с некоторыми исключениями с помощью регулярных выражений?

У меня есть регулярное выражение /^\[(text:\s*.+?\s*)\]/mi, которое в настоящее время работает при захвате текста в скобках, начинающихся с text:. Вот пример, где он работает:

[text: here is my text that is
captured within the brackets.]

Теперь я хотел бы добавить исключение, чтобы оно допускало определенные скобки, как в следующем случае:

[text: here is my text that is
captured within the brackets
and also include ![](/some/path)]

В принципе, мне нужно это, чтобы скобки ![](/some/path) совпадали.

Любая помощь будет принята с благодарностью. Спасибо.

Update:

Вот некоторые случаи, когда текст внутри скобок должен быть сопоставлен:

[text: here is my text that is
captured within the brackets
and also include ![](/some/path)]

[text: here is my text that is
captured within the brackets
and also include ![](/some/path) and some more text]

[text: ![](/some/path)]

![text: cat]

Вот некоторые случаи, когда он не должен совпадать:

[text: here is my text that is
captured within the brackets
and also include ![invalid syntax](/some/path)]

[text: here is my text that is
captured within the brackets
and also include ![] (/some/path)]

[text: here is my text that is
captured within the brackets
and also include ! [](/some/path)]

[text: here is my text that is
captured within the brackets
and also include ! [] (/some/path)]

Ответ 1

ОК, поэтому вы хотите разрешить либо

  • символ, который не является скобкой или
  • последовательность ![]

между стартовой и конечной скобками. Это дает вам регулярное выражение

/^\[(text:[^\[\]]*(?:!\[\][^\[\]]*)*)\]/mi

Объяснение:

^           # Start of line
\[          # Match [
(           # Start of capturing group
 text:      # Match text:
 [^\[\]]*   # Match any number of characters except [ or ]
 (?:        # Optional non-capturing group:
  !\[\]     #  Match ![]
  [^\[\]]*  #  Match any number of characters except [ or ]
 )*         # Repeat as needed (0 times is OK)
)           # End of capturing group
\]          # Match ]

Протестируйте его в прямом эфире на regex101.com.

Ответ 2

Вы можете использовать регулярное выражение, слегка измененное и упрощенное.

str =<<_
[text: here is my text that is
captured within the brackets
and also includes ![](/some/path)]
and other stuff
_

r = /
    ^       # match beginning of string
    \[text: # match string
    .+?     # match one or more characters lazily
    \]      # match right bracket
   /imx      # case indifferent (i), multiline (m) and extended/free-spacing (x) modes

PLACEHOLDER = 0.chr
SUBSTITUTE_OUT = '![](/'

puts str.gsub(SUBSTITUTE_OUT, PLACEHOLDER).
  scan(r).
  map { |s| s.gsub(PLACEHOLDER, SUBSTITUTE_OUT) }

[text: here is my text that is
captured within the brackets
and also includes ![](/some/path)]

Обратите внимание, что в регулярном выражении \s*.+?\s* совпадает с .+? и (как отмечалось в @sawa) вы можете заменить .+? на [^\]]+, и в этом случае вам не понадобится многострочный режим.

Изменить: я обновил SUBSTITUTE_OUT в свете редактирования вопроса в OP. Это иллюстрирует одно преимущество этого подхода: на регулярное выражение не влияют изменения во внутреннем совпадающем тексте.

Ответ 3

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

^\[(text:.+?)(?<!\[)\]

Здесь прохождение.

^           # Start of line anchor.
\[          # Match opening bracket '['
(           # Start capturing group 1. 
text:       # Match 'text:'
.+?         # Match any character one or more times lazily.
)           # End capturing group 1. 
(?<!        # Begin negative lookbehind.
\[          # '[' must not preceed the next match.
)           # End negative lookbehind.
\]          # Match closing bracket.

Здесь демонстрация.

Ответ 4

Я не понимаю, как новый символ строки имеет отношение к тому, что вы описываете, поэтому я удалил ^.

/\[(text:(?:[^\[\]]|!\[\][/\w]+)+)\]/i

Ответ 5

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

^\[(text:.*?(?<!\[))\]