2010-02-01 116 views
3

我正在使用Python 2.6.4。Python中的遞歸嵌套表達式

我在文本文件中有一系列選擇語句,我需要從每個選擇查詢中提取字段名稱。如果某些字段沒有使用像to_char()等嵌套函數,那麼這很容易。

給定select語句字段可能有幾個嵌套圓括號,比如「ltrim(rtrim(to_char(base_field_name,format)))renamed_field_name ,「或只是」base_field_name「作爲字段的簡單情況,是否可以使用Python的re模塊編寫正則表達式來提取base_field_name?如果是這樣,正則表達式會是什麼樣子?

回答

2
>>> import re 
>>> string = 'ltrim(rtrim(to_char(base_field_name, format))) renamed_field_name' 
>>> rx = re.compile('^(.*?\()*(.+?)(,.*?)*(,|\).*?)*$') 
>>> rx.search(string).group(2) 
'base_field_name' 
>>> rx.search('base_field_name').group(2) 
'base_field_name' 
+2

PS世界:亞歷克斯·馬爾泰利的告訴,你應該使用一個真正的解析器在這裏。無論如何,如果你只想要一個快速的正則表達式,你可以使用它。但你應該真的使用一個解析器,因爲這個正則表達式看起來相當難看:) – 2010-02-01 01:00:34

+0

我並沒有追求一些看起來很漂亮的東西,因爲它是一個讓我獲得我想要的數據的工具,所以我可以用它來做其他事情。 :)但是,謝謝,我的正則表達式是生鏽的,我想有人可能會更好地知道。 – TheObserver 2010-02-01 01:15:09

11

正則表達式不適合解析「嵌套」結構。相反,嘗試使用完整的解析工具包,例如pyparsing - 例如,專門用於解析SQL的pyparsing的示例可以找到herehere,例如(您無疑需要將示例作爲起點,並且寫一些你自己的解析代碼,但是,它絕對不是太難)。

+1

+1記住的是,良好的括號表達式(當然,所有喬姆斯基型2種語言)需要比正則表達式更正確解析:) – Agos 2010-02-01 00:46:12

2

或者像Alex Martelli建議的表驅動解析器或手寫遞歸下降解析器。他們不難,寫作也很有意義。

1

這可能是不夠好:

import re 
print re.match(r".*\(([^\)]+)\)", "ltrim(to_char(field_name, format)))").group(1) 

您需要做進一步的處理。例如,選取函數名稱,並根據函數簽名提取字段名稱。

.*(\w+)\(([^\)]+)\) 
+0

這爲我打印'field_name,format',而不是'field_name',也不適用於簡單字符串'field_name'。 – 2010-02-01 00:47:57

+0

你怎麼知道每個函數都會接受相同的參數? – ziya 2010-02-01 01:20:11

0

你真的需要正則表達式嗎?爲了得到你在那裏得到的那個,我會用

s[s.rfind('(')+1:s.find(')')].split(',')[0] 

's'包含原始字符串。

當然,這不是一般的解決辦法,但...

+0

編譯後的正則表達式應該比這更快。那麼,我想我們並不着急,但仍然只是爲了提高效率。 – 2010-02-01 01:30:15

+0

您可能會發現直接使用字符串更快。 很大程度上取決於正則表達式和您需要編寫的等效代碼的複雜性,以便在沒有正則表達式的情況下執行此操作。 其實,你有沒有試過比較它們? – 2010-02-01 01:59:16

+1

哦,如果我想要去等效的正則表達式,我會使用「\\(([^(),] +),」,它比純粹的基於字符串的稍快。 他們都比你的正則表達式快一個數量級... – 2010-02-01 02:30:00

1

這裏是一個非常哈克解析器,你想要做什麼。

它通過調用要解析的文本'eval',將所有標識符映射到返回其第一個參數的函數(我猜是你想要的例子)。

class FakeFunction(object): 
    def __init__(self, name): 
     self.name = name 
    def __call__(self, *args): 
     return args[0] 
    def __str__(self): 
     return self.name 

class FakeGlobals(dict): 
    def __getitem__(self, x): 
     return FakeFunction(x) 

def ExtractBaseFieldName(x): 
    return eval(x, FakeGlobals()) 

print ExtractBaseFieldName('ltrim(rtrim(to_char(base_field_name, format)))')