Регулярные выражения отрицательного просмотра вперед
Я делаю гимнастику регулярного выражения. Я поставил перед собой задачу попытаться найти код C#, где есть использование as-оператора, за которым не следует нулевая проверка в разумном объеме пространства. Сейчас я не хочу анализировать код на C#. Например. Я хочу захватить фрагменты кода, такие как
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)
, не
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1 == null)
не
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(somethingunrelated == null) {...}
if(x1.a == y1.a)
таким образом, любая случайная нулевая проверка будет считаться "хорошей проверкой" и, следовательно, не найдено.
вопрос: как мне сопоставить что-то, гарантируя, что что-то еще не найдено в его sourroundings.
Я пробовал наивный подход, ища "как", а затем делал отрицательный lookahead в пределах 150 символов.
basb.{1,150}(?!b==s*nullb)
приведенное выше регулярное выражение соответствует всем приведенным выше примерам, к сожалению. Моя интуиция говорит мне, проблема в том, что глядя вперед, а затем делать отрицательный взгляд может найти много ситуаций, когда lookahead не находит '== null'.
если я попытаюсь отрицать все выражение, то это тоже не поможет, при этом будет соответствовать большинству кода C#.
6 ответов
Я любовь regex гимнастика! Вот комментарий PHP regex:
$re = '/# Find all AS, (but not preceding a XX == null).
\bas\b # Match "as"
(?= # But only if...
(?: # there exist from 1-150
[\S\s] # chars, each of which
(?!==\s*null) # are NOT preceding "=NULL"
){1,150}? # (and do this lazily)
(?: # We are done when either
(?= # we have reached
==\s*(?!null) # a non NULL conditional
) #
| $ # or the end of string.
)
)/ix'
и вот он в стиле Javascript:
re = /\bas\b(?=(?:[\S\s](?!==\s*null)){1,150}?(?:(?===\s*(?!null))|$))/ig;
от этого у меня немного болела голова...
вот тестовые данные, которые я использую:
text = r""" var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)
however, not capture
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1 == null)
nor for that matter
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(somethingunrelated == null) {...}
if(x1.a == y1.a)"""
поставить .{1,150}
внутри lookahead и замените .
С \s\S
(вообще, .
не соответствует новым строкам). Кроме того,\b
может вводить в заблуждение возле ==
.
\bas\b(?![\s\S]{1,150}==\s*null\b)
Я думаю, что это поможет поместить имя переменной в (), чтобы вы могли использовать его в качестве обратной ссылки. Что-то вроде следующего,
\b(\w+)\b\W*=\W*\w*\W*\bas\b[\s\S]{1,150}(?!\b\b\W*==\W*\bnull\b)
вопрос не понятен. Чего именно ты хочешь ? Я сожалею, но я все еще не понимаю, прочитав вопрос и комментарии много раз.
.
должен ли код быть на C# ? В Python ? Другие ? Нет никаких указаний относительно этого пункта
.
вы хотите соответствие только если if(... == ...)
строка следует за блоком var ... = ...
линии ?
или может быть гетерогенная линия между блоком и if(... == ...)
линия без остановки сопоставления ?
мой код принимает второй вариант как true.
.
тут if(... == null)
строка после if(... == ...)
остановка в комплекте или нет ?
невозможно понять, да или нет, я определил два регулярных выражения, чтобы поймать эти два варианта.
.
Я надеюсь, что мой код будет достаточно ясным и ответит на вашу озабоченность.
это в Питон
import re
ch1 ='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)
1618987987849891
'''
ch2 ='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
uydtdrdutdutrr
if(x1.a == y1.a)
3213546878'''
ch3='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1 == null)
165478964654456454'''
ch4='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
hgyrtdduihudgug
if(x1 == null)
165489746+54646544'''
ch5='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(somethingunrelated == null ) {...}
if(x1.a == y1.a)
1354687897'''
ch6='''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
ifughobviudyhogiuvyhoiuhoiv
if(somethingunrelated == null ) {...}
if(x1.a == y1.a)
2468748874897498749874897'''
ch7 = '''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)
iufxresguygo
liygcygfuihoiuguyg
if(somethingunrelated == null ) {...}
oufxsyrtuy
'''
ch8 = '''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
tfsezfuytfyfy
if(x1.a == y1.a)
iufxresguygo
liygcygfuihoiuguyg
if(somethingunrelated == null ) {...}
oufxsyrtuy
'''
ch9 = '''kutgdfxfovuyfuuff
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
tfsezfuytfyfy
if(x1.a == y1.a)
if(somethingunrelated == null ) {...}
oufxsyrtuy
'''
pat1 = re.compile(('('
'(^var +\S+ *= *\S+ +as .+[\r\n]+)+?'
'([\s\S](?!==\s*null\b))*?'
'^if *\( *[^\s=]+ *==(?!\s*null).+$'
')'
),
re.MULTILINE)
pat2 = re.compile(('('
'(^var +\S+ *= *\S+ +as .+[\r\n]+)+?'
'([\s\S](?!==\s*null\b))*?'
'^if *\( *[^\s=]+ *==(?!\s*null).+$'
')'
'(?![\s\S]{0,150}==)'
),
re.MULTILINE)
for ch in (ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8,ch9):
print pat1.search(ch).group() if pat1.search(ch) else pat1.search(ch)
print
print pat2.search(ch).group() if pat2.search(ch) else pat2.search(ch)
print '-----------------------------------------'
результат
>>>
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)
-----------------------------------------
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
uydtdrdutdutrr
if(x1.a == y1.a)
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
uydtdrdutdutrr
if(x1.a == y1.a)
-----------------------------------------
None
None
-----------------------------------------
None
None
-----------------------------------------
None
None
-----------------------------------------
None
None
-----------------------------------------
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
if(x1.a == y1.a)
None
-----------------------------------------
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
tfsezfuytfyfy
if(x1.a == y1.a)
None
-----------------------------------------
var x1 = x as SimpleRes;
var y1 = y as SimpleRes;
tfsezfuytfyfy
if(x1.a == y1.a)
None
-----------------------------------------
>>>
позвольте мне попытаться переопределить вашу проблему:
- ищите назначение" как " -- вам, вероятно, нужно лучшее регулярное выражение для поиска фактических назначений и может потребоваться сохранить назначенное выражение, но давайте использовать "\bas\b" сейчас
- если вы видите
if (... == null)
в 150 символов, не соответствуют - если вы не видите
if (... == null)
в пределах 150 символов, матч
выражение \bas\b.{1,150}(?!\b==\s*null\b)
не будет работать из-за негативного взгляда вперед. Регулярное выражение всегда может пропустить вперед или позади одной буквы, чтобы избежать этого негативного взгляда вперед, и вы в конечном итоге совпадаете, даже если есть if (... == null)
там.
Regex действительно не хороши в не что-то сопоставления. В этом случае вам лучше попытаться сопоставить назначение "as" с проверкой "if == null" в пределах 150 символов:
\bas\b.{1,150}\b==\s*null\b
и затем отрицание чека:if (!regex.match(text)) ...
(?s:\s+as\s+(?!.{0,150}==\s*null\b))
я активирую опцию SingleLine с помощью ?s:
. Вы можете поместить его в параметры вашего регулярного выражения, если хотите. Добавлю, что ставлю \s
вокруг as
потому что я думаю, что только пробелы "правового" вокруг as
. Вы, вероятно, можете поставить \b
как
(?s:\b+as\b(?!.{0,150}==\s*null\b))
имейте в виду, что \s
вероятно, поймает пробелы, которые не являются "допустимыми пробелами". Это определяется как [\f\n\r\t\v\x85\p{Z}]
здесь \p{Z}
is символы Юникода в 'Пробел' Категория плюс символы Юникода в категории "разделитель, строка" плюс символы Юникода в категории "разделитель, абзац".