Регулярное выражение заменяет символ в соответствии с вложенными круглыми скобками или заменяет только в тексте вне соответствия - PullRequest
0 голосов
/ 09 июля 2020

Я пишу сценарий AutoHotkey, который будет форматировать SQL операторов из текста, выбранного на экране. Я хочу превратить такой оператор:

SELECT Name AS [Object Name], Switch([Type]=5,'Query',[Type]=-32768,'Form',[Type]=6,'Table') AS [Object Type], Switch([Type]=5,1,[Type]=-32768,2,[Type] In (1,4,6),6) AS [Object Type ID], Left(Name,4) as Prefix, LTrim(RTrim(Mid([Name],5,30))) as Suffix

в это:

SELECT Name AS [Object Name], 
    Switch([Type]=5,'Query',[Type]=-32768,'Form',[Type]=6,'Table') AS [Object Type], 
    Switch([Type]=5,1,[Type]=-32768,2,[Type] In (1,4,6),6) AS [Object Type ID], 
    Left(Name,4) as Prefix,
    LTrim(RTrim(Mid([Name],5,30))) as Suffix

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

; Find commas not in parenthesis and suffix with <CR><Tab>
s := RegExReplace( s, ",(?![^()]*\))", ",`r`n" . Tab )

Проблема в том, что иногда скобки вставлены, и этот простой RegEx не работает.

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

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

Теперь проблема в том,

  1. как мне выберите все за пределами этой группы и найдите / замените в ней, или
  2. как применить поиск / замену только к тексту внутри этой группы?

Regex Demo

ТАК побуждает нас ответить на наш собственный вопрос. В процессе написания я нашел решение и опубликую его ниже. Не стесняйтесь делиться собственными решениями. Я хотел бы глубже понять регулярные выражения.

1 Ответ

0 голосов
/ 09 июля 2020

Я обнаружил, что могу использовать или в своем выражении, чтобы найти что-либо в скобках ИЛИ любую запятую. С помощью этого метода он не выбирает отдельные запятые, которые находятся внутри групп скобок. (Спасибо zx81 в этом сообщении.)

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

С этим выражением я могу использовать замену |$0|, чтобы окружить каждую соответствующую группу символом | персонаж. Тогда легко найти отдельные запятые с помощью |,| и заменить их моим шаблоном возврата каретки, а затем заменить все оставшиеся | пустой строкой.

; AutoHotkey snippet below
s := RegExReplace( s, ",|\((?:[^()]++|(?R))*\)", "|$0|" )
s := StrReplace( s, "|,|" , ",`r`n" . A_Tab )
s := StrReplace( s, "|" , "")

Regex пример замены

...