[英]dynamically generate regex from the keys of the dictionary python
def t_FUNC_(self, t):
r'(?i)I|(?i)J|(?i)K|(?i)L|(?i)M|(?i)N|(?i)Y'
return t
在上面的函數中,我返回一個正則表達式,這意味着FUNC可以是I或J或K或L或M或N或Y.
現在,我有一個字典,如:
dic = { 'k1':'v1', 'k2':'v2' }
我可以在上面的函數中訪問這個字典。 如何從字典的鍵動態生成正則表達式。 字典的大小也不固定。
所以,我想要替換r'(?i)I|(?i)J|(?i)K|(?i)L|(?i)M|(?i)N|(?i)Y'
像r'(?i)k1|(?i)k2
。
PS:當我們在python中使用ply庫編寫lexer時,上面的模式代碼用於生成標記。
將dict的鍵放入你的正則表達式就像這樣簡單:
regex = '|'.join('(?i){}'.format(k) for k in data)
data = {'k1': 'v1', 'k2': 'v2'}
regex = '|'.join('(?i){}'.format(k) for k in data)
print(regex)
(?i)k1|(?i)k2
正如@AustinHastings在評論中所說,Ply通過組合詞法分析器類中提供的正則表達式來構建詞法掃描器,作為類成員的值或作為類成員函數的文檔字符串。 一旦構建了掃描儀,它就不會被修改,所以你真的無法動態調整正則表達式,至少在生成掃描儀之后是這樣。
但是,對於您想到的特定應用程序,不必創建自定義正則表達式。 您可以使用Ply手冊中說明的更簡單的過程, 該過程顯示如何識別保留字,而不為每個單詞使用自定義正則表達式。
這個想法非常簡單。 保留字 - 在您的情況下的函數名稱 - 通常是已經在詞法掃描器中使用的一些更一般模式的特定示例。 幾乎可以肯定的是,因為詞匯掃描程序必須以某種方式識別每個標記,所以在將動態生成的單詞添加到掃描程序之前,它必須已被識別為其他內容。 我們只是讓令牌被識別,然后在返回令牌之前更正其類型(可能還有其值),而不是嘗試覆蓋特定實例的其他模式。
以下是Ply手冊中示例的略微修改版本:
def t_ID(t):
r'[a-zA-Z_][a-zA-Z_0-9]*'
# Apparently case insensitive recognition is desired, so we use
# the lower-case version of the token as a lookup key. This means
# that all the keys in the dictionary must be in lower-case
token = t.value.lower()
if token in self.funcs:
t.type = 'FUNC'
return t
(您可能希望調整上面的內容,以便它使用與funcs
字典中的鍵相關聯的值執行某些操作,盡管稍后在語義分析期間也可以這樣做。)
由於funcs
字典不以任何方式參與詞法分析器(或解析器)的生成,因此不需要特別的聰明才能將其傳遞給Lexer對象。 實際上,它甚至不需要在詞法分析器對象中; 您可以在構造詞法分析器對象時將解析器對象添加到詞法分析器對象,允許您將詞典放入解析器對象中,解析器操作更容易訪問該對象。
這是一個比嘗試構建自定義正則表達式更好的解決方案的原因之一是它不能識別恰好被發現為非保留字的前綴的保留字。 例如,如果cos
是其中一個函數,並且您已設法生成等效函數
t_ID = r'[a-zA-Z_][a-zA-Z_0-9]*'
def t_FUNC(t):
r'(?i)sin|cos|tan'
# do something
然后你會發現:
cost = 3
被掃描為FUNC(cos), ID(t), '=', NUMBER(3)
,這幾乎肯定不是你想要的。 將邏輯放在t_ID
函數內完全避免了這個問題,因為只考慮完整的令牌。
'(?i)'+'|'.join(re.escape(k) for k in dic)
如果其中一個dic
鍵恰好包含正則表達式語言中的控制字符(如|
),則需要re.escape
。 此外,像(?i)
這樣的全局內聯標志的使用在模式中的任何地方都被棄用,但是在開始時。 (如果您只希望它應用於表達式的一部分,則可以使用新的本地標志語法(?i:foo)
。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.