[英]Python regex for select/extract from nested groups
我正在嘗試使用CHAR(int)和NCHAR(int)處理一個字符串,以使用其ASCII計數器轉換這些實例。 一個例子是這樣的:
CHAR(124) + (SELECT TOP 1 CAST(name AS VARCHAR(8000)) FROM (SELECT TOP 1 colid, name FROM [Projects]..[syscolumns]
WHERE xtype=char(85)
AND id = OBJECT_ID(NCHAR(69)+NCHAR(78)+NCHAR(95)+NCHAR(69)+NCHAR(109)+NCHAR(112)+NCHAR(108))
請注意,我不想對VARCHAR(int)做任何事情,而只對CHAR(int)和NCHAR(int)部分做任何事情。 上面的應該翻譯為:
|(選擇頂部1個CAST(名稱為VARCHAR(8000)),來自(選擇頂部1個colid,名稱為[項目] .. [syscolumns]),其中xtype = U AND id = OBJECT_ID(EN_Empl)
請注意,應刪除CHAR(int)或NCHAR(int)兩側的任何“ +”號。 我嘗試了以下方法:
def conv(m):
return chr(int(m.group(2)))
print re.sub(r'([\+ ]?n?char\((.*?)\)[\+ ]?)', conv, str, re.IGNORECASE)
其中str
=必須處理的原始字符串。
不知何故,VARCHAR(8000)被拾取。 如果我調整正則表達式,則xtype之后的“ =”將會消失,而不僅僅是CHAR(int)或NCHAR(int)實例兩側的空格和“ +”。
希望有人可以把我從中拉出來。
其他示例字符串:
字符串"char(124)+(Select Top 1 cast(name as varchar(8000)) from (Select Top 1 colid,name From [Projects]..[syscolumns] Where id = OBJECT_ID(NCHAR(69)+NCHAR(78)+NCHAR(95)+NCHAR(69)+NCHAR(109)+NCHAR(112)+NCHAR(108)))"
正則表達式: r'(\\bn?char\\((\\d+)\\)(?:\\s*\\+\\s*)?)'
結果: "|(Select Top 1 cast(name as varchar(8000)) from (Select Top 1 colid,name From [Projects]..[syscolumns] Where id = OBJECT_ID(ENCHAR(78)+NCHAR(95)+NCHAR(69)+NCHAR(109)+NCHAR(112)+NCHAR(108)))"
您有三個問題:
flags=re.IGNORECASE
,而不僅僅是re.sub中的 re.IGNORECASE
。 那是一個關鍵字參數。 \\b
查找單詞邊界。 str
作為名稱,因為您將用相同的名稱覆蓋內置文件 這有效:
import re
tgt='''\
CHAR(124) + (SELECT TOP 1 CAST(name AS VARCHAR(8000)) FROM (SELECT TOP 1 colid, name FROM [Projects]..[syscolumns]
WHERE xtype=char(85)
AND id = OBJECT_ID(NCHAR(69)+NCHAR(78)+NCHAR(95)+NCHAR(69)+NCHAR(109)+NCHAR(112)+NCHAR(108))'''
pat=r'(\bn?char\((\d+)\)(?:\s*\+\s*)?)'
def conv(m):
return chr(int(m.group(2)))
print re.sub(pat, conv, tgt, flags=re.IGNORECASE)
更完整地:
import re
tgt='''\
CHAR(124) + (SELECT TOP 1 CAST(name AS VARCHAR(8000)) FROM (SELECT TOP 1 colid, name FROM [Projects]..[syscolumns]
WHERE xtype=char(85)
AND id = OBJECT_ID(NCHAR(69)+NCHAR(78)+NCHAR(95)+NCHAR(69)+NCHAR(109)+NCHAR(112)+NCHAR(108))'''
pat=r'(\bn?char\((\d+)\)(?:\s*\+\s*)?)'
def conv(m):
return chr(int(m.group(2)))
print re.sub(r'''
( # group 1
\b # word boundary
n?char # nchar or char
\( # literal left paren
(\s*\d+\s*) # digits surrounded by spaces
\) # literal right paren
(?:\s*\+\s*)? # optionally followed by a concating '+'
) '''
, conv, tgt, flags=re.VERBOSE | re.IGNORECASE)
印刷品:
|(SELECT TOP 1 CAST(name AS VARCHAR(8000)) FROM (SELECT TOP 1 colid, name FROM [Projects]..[syscolumns]
WHERE xtype=U
AND id = OBJECT_ID(EN_Empl)
您只需添加單詞boundary( \\b
)斷言就可以走很長一段路,但是我建議您(1)使用re.VERBOSE
編寫一個以后可以理解的正則表達式; (2)編譯正則表達式以減少呼叫現場的混亂情況; (3)加強一些匹配標准。 像這樣:
def conv(m):
return chr(int(m.group(1)))
pat = re.compile(r"""[+\s]* # optional whitespace or +
\b # word boundary
n?char # NCHAR or CHAR
\( # left paren
([\d\s]+) # digits or spaces - group 1
\) # right paren
[+\s]* # optional whitespace or +
""", re.VERBOSE | re.IGNORECASE)
print pat.sub(conv, data)
請注意,我將您的str
更改為data
: str
是一個經常使用的內置函數的名稱,創建具有相同名稱的變量是一個絕妙的主意。
您只需要使用單詞邊界\\b
:
def conv(m):
return chr(int(m.group(1)))
print re.sub(r'\bn?char\(([^)]+)\)(?:\s*\+\s*)?', conv, str, re.IGNORECASE)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.