2010-07-15 214 views
1

我有這樣的正則表達式:爲什麼這個正則表達式匹配?

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

而且我想它來搭配這樣的:

MSGBOX(「總運行時間來修復區和TD領域是:」 & = imeElapsed &「分鐘「)

但不是這樣的:

子ChangeAreaTD()

但一些我怎麼仍然匹配以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 ")". 

,然後去比賽的內容組012.

但是,正則表達式通常是嚴重不適合解析代碼。對於HTML而言,這與VB代碼的情況一樣。即使改進了正則表達式,你也會得到錯誤的匹配。例如,在這裏,因爲嵌套的父親:

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

哦,我明白了爲什麼現在失敗。你會推薦另一種解析代碼的方法嗎? 我用正則表達式去了,因爲我注意到關於VBA的一件事是每個定義總是隻有一行。與C#不同的是,例如,如果(())和下一行中的括號相同,則VBA始終將所有內容保留爲一行。 – 2010-07-16 09:22:45

+0

@Tiago:這不完全正確。您可以在一行的末尾插入下劃線,並將其視爲續行。你可以用冒號分隔兩個邏輯代碼行('Dim x:x = 10')。對於解析語言,請始終使用解析器。不知道是否有一個解析器可以用來解析VB代碼,但不應該寫太難。不過,這是一個單獨問題的材料。 – Tomalak 2010-07-16 10:10:04

+0

好悲傷..我不知道下劃線,或者說,我從VB .NET知道它,我只是不認爲它也適用於VBA。我只是查了一下,它和冒號一樣。 我想我最終會用'\ r \ n'替換冒號並刪除'_ \ r \ n'的所有實例,因爲下劃線必須是該行的最後一個字符。 我試過尋找一個VBA的解析器,似乎沒有一個,再加上我有大約三個月的時間想出創建一個抽象的語法樹出VBA代碼,然後生成C#出AST。 – 2010-07-16 11:16:24

3

這樣做:

^MsgBox .*\(.*\)

的問題是負回顧後並不能保證一個字符串的開頭。它會匹配任何地方。

但是,在正則表達式的開頭添加一個^字符確保字符串的開頭。然後,將Sub更改爲MsgBox,以便它只匹配以MsgBox

+2

在這種情況下,後視沒有意義,因爲在字符串開始之前不能有任何東西。 – Gumbo 2010-07-15 16:26:25

+0

嗯謝謝你我已經修復了它 – 2010-07-15 23:55:31

+0

這會幫助我,如果我只是想抓住MsgBox調用,但我從原始問題中省略的一件事是,我實際上試圖抓取所有的方法調用,但沒有方法聲明。 所以我需要的是: <任何字符不是「Sub」>(<任何字符>) – 2010-07-16 09:19:31

1

開頭的字符串。這裏有一個回溯問題。 (?<!Sub).*\(.*\)中的第一個.*可以匹配ChangeAreaTD或hangeAreaTD。在後一種情況下,前4個字符是ub C,與Sub不匹配。當後視被否定時,這就相當於一場比賽!

只要將^添加到您的正則表達式的開頭並不會對您有所幫助,因爲後視是零長度匹配短語。 ^(?<!MsgBox)將尋找一條以MsgBox結尾的行。你需要做的是^(?!Sub)(.*\(.*\))。這可以解釋爲「從字符串的開頭開始,確保它不以Sub開頭,然後,如果它看起來像方法調用,則捕獲字符串中的所有內容」。

正則表達式引擎解析lookaround的一個很好的解釋可以找到here

0

如果您只想匹配函數調用而不是聲明,那麼預括號匹配不應匹配任何字符,但更可能是任何標識符字符後跟空格。因此,

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

標識符可能需要更多的標記,具體取決於您匹配的語言。

相關問題