2010-07-15 4 views
1

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

(?<!Sub).*\(.*\) 

И я хотел бы, чтобы соответствовать этому:

MsgBox («Общее время работы, чтобы исправить AREA и TD поля является:» & = imeElapsed & "минут ")

Но не так:.

Sub ChangeAreaTD()

Но некоторые как я все еще согласен с тем, что начинается с Sub ... кто-нибудь может понять, почему? Я думал, что будет исключением «Sub», делая

(?<!Sub)

Любая помощь приветствуется!

Спасибо.

ответ

2

Ваше регулярное выражение (?<!Sub).*\(.*\), разобрали:

(?<!   # negative look-behind 
    Sub  # the string "Sub " must not occur before the current position 
)   # end negative look-behind 
.*   # anything  ~ matches up to the end of the string! 
\(   # a literal "(" ~ causes the regex to backtrack to the last "(" 
    .*   # anything  ~ matches up to the end of the string again! 
\)   # a literal ")" ~ causes the regex to backtrack to the last ")" 

Так, с тестовой строки:

 
Sub ChangeAreaTD() 
  • Взгляд-за выполняется сразу (справа в положении 0).
  • .* отправляется в конец строки после этого.
  • Из-за этого .* внешний вид никогда не имеет значения.

Вы, вероятно, думаете о

 
(?<!Sub .*)\(.*\) 

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

Так что я хотел бы сделать это (с переменной длиной упреждающая широко поддерживается):

 
^(?!.*\bSub\b)[^(]+\(([^)]+)\) 

, что переводится как:

^   # At the start of the string, 
(?!   # do a negative look-ahead: 
    .*  # anything 
    \b  # a word boundary 
    Sub  # the string "Sub" 
    \b  # another word bounday 
)   # end negative look-ahead. If not found, 
[^(]+  # match anything except an opening paren ~ to prevent backtracking 
\(   # match a literal "(" 
(   # match group 1 
    [^)]+  # match anything up to a closing paren ~ to prevent backtracking 
)   # end match group 1 
\)   # match a literal ")". 

, а затем пойти на содержание матча группа 1.

Однако, регулярное выражение, как правило, плохо подходит для анализа кода. Это верно для HTML так же, как и для кода VB. Вы получите неправильные совпадения даже с улучшенным регулярным выражением. Например, из-за вложенных парнеров:

 
MsgBox ("The total run time to fix all fields (AREA, TD) is: ...") 
+0

О, я понимаю, почему это не удается сейчас. Не могли бы вы порекомендовать другой способ для анализа кода? Я пошел с регулярным выражением, потому что одна из вещей, которые я заметил о VBA, заключается в том, что каждое определение всегда имеет только одну строку. В отличие от C#, где вы можете, например, иметь (), а затем скобку в следующей строке, VBA всегда держит все в одной строке. –

+0

@Tiago: Это не совсем так. Вы можете вставить подчеркивание в конце строки, и это считается продолжением строки. Вы можете разделить две логические строки кода с двоеточием ('Dim x: x = 10'). Для разбора языков всегда используйте синтаксический анализатор. Не уверен, есть ли синтаксический анализатор, который вы можете использовать для разбора кода VB, но его не должно быть сложно записать. Тем не менее, это материал для отдельного вопроса. – Tomalak

+0

Хорошее горе. Я не знал о знаке подчеркивания, или, вернее, знал об этом с VB .NET, я просто не думал, что это применимо и к VBA. Я просто проверил, и это так, как и двоеточие. Я думаю, что я просто закончу замену двоеточий '\ r \ n' и удалю все экземпляры '_ \ r \ n', поскольку подчеркивание должно быть последним символом в строке для его работы. Я пробовал искать парсер для VBA и, похоже, не один, плюс у меня есть около трех месяцев, чтобы придумать что-то, что создает абстрактное синтаксическое дерево из кода VBA, а затем что-то другое, которое генерирует C# из этого АСТ. –

3

ли это:

^MsgBox .*\(.*\)

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

Однако добавление символа ^ в начале регулярного выражения гарантирует начало строки. Затем измените Sub на MsgBox, так что он соответствует только строкам, которые начинаются с MsgBox

+2

В этом случае внешний вид не имеет смысла, поскольку перед началом строки ничего не может быть. – Gumbo

+0

Благодарю вас, я исправил его –

+0

Это помогло бы мне, если бы я просто пытался захватить вызовы MsgBox, но одна вещь, которую я пропустил из исходного вопроса, состояла в том, что я на самом деле пытаюсь захватить все вызовы методов, но не объявления методов. Так что мне нужно: <любые символы, которые не являются «Sub»> () –

1

У вас проблема с возвратом. Первый .* в (?<!Sub).*\(.*\) может соответствовать ChangeAreaTD или hangeAreaTD. В последнем случае предыдущие 4 символа: ub C, который не соответствует Sub. Поскольку lookbehind отрицается, это считается совпадением!

Просто добавление ^ в начало вашего регулярного выражения вам не поможет, так как look-behind - это фраза с нулевой длиной. ^(?<!MsgBox) будет искать строку, которая следует за строкой, заканчивающейся в MsgBox. Вместо этого вам нужно сделать ^(?!Sub)(.*\(.*\)). Это можно интерпретировать как «Начиная с начала строки, убедитесь, что она не начинается с Sub. Затем запишите все в строке, если она похожа на вызов метода».

Хорошее объяснение того, как выглядят поисковые системы регулярных выражений here.

0

Если вы хотите соответствовать только вызовам функций, а не объявлению, то совпадение перед скобками не должно совпадать с любыми символами, но, скорее, любые символы идентификатора, за которыми следуют пробелы. Таким образом,

(?<!Sub)[a-zA-Z][a-zA-Z0-9_]* *\(.*\) 

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

Смежные вопросы