2013-12-14 104 views
0

我想處理一個字符串與CHAR(INT)和NCHAR(INT)來轉換這些實例與他們的ASCII計數器部分。一個例子是這樣的:只有Python的正則表達式從嵌套組中選擇/提取

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)部分。以上應該轉換爲:

|(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)

注意,任何 「+」 上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)正在拾取。如果我調整了reg ex,xtype消失後的「=」,而不僅僅是CHAR(int)或NCHAR(int)實例兩側的空格和「+」。

希望有人能把我拉出來。

補充樣品STRINGS:

字符串"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)))"

回答

1

你可以通過添加單詞邊界(\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) 

請注意,我改變了你的strdatastr是一個頻繁使用的內置函數的名稱,這是一個非常糟糕的主意,以創建具有相同名稱的變量。

+0

謝謝@Tim Peters。讚賞提高可讀性的建議;它也能幫助我(別說別人了!)。我確實嘗試過,它似乎工作!有一件事我不明白分組+搜索+替換正則表達式中的作品。我最初在另一個組中創建了一個組(對於要轉換爲其ASCII等效值的組)(封裝了[+]和[N] CHAR(int)實例的空白)。您的正則表達式會刪除任何周圍的「+」或空白字符,即使它不是該組的一部分。我必須花更多時間用正則表達式的基礎。謝謝你的幫助! –

+1

不客氣:-)'sub()'替換了正則表達式匹配的整個子字符串,所以實際上並不需要最外層的組。這就是我刪除它的原因。儘管如此,我們仍然需要一個組來隔離數字,以便'conv()'可以輕鬆找到它們。但是'conv()'的輸出替換了正則表達式匹配的*整個*子字符串。也許有點微妙,但你會很快適應它;-) –

+0

感謝@蒂姆彼得斯非常有幫助的解釋和答案! –

0

你只需要使用一個單詞邊界\b

def conv(m): 
    return chr(int(m.group(1))) 

print re.sub(r'\bn?char\(([^)]+)\)(?:\s*\+\s*)?', conv, str, re.IGNORECASE) 
2

你有三個問題:

  1. 您需要使用flags=re.IGNORECASE並不僅僅是re.IGNORECASEre.sub。這是一個關鍵字參數。
  2. 您需要使用\b來查找單詞邊界。
  3. 你不應該使用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) 
+0

我用你的表情,我覺得我更近了一步!但是,如果你看看我提供的新示例,在我提出的正則表達式中提供了你正在提供的正則表達式,你會發現用「+」分隔的一系列nchar(int)實例似乎只轉換第一個實例,剩下的實例是按原樣保存。有什麼建議麼? NCHAR(69)被替換爲「E」,但其他一切都保持不變。 –

+0

你使用了關鍵字're.sub(...,flags = re.IGNORECASE)'嗎? – dawg

+0

是的,我使用了IGNORECASE標誌。蒂姆彼得斯的答案爲我工作。我認爲你的答案和他的區別在於,他在前後需要添加「+」和空白部分。謝謝你的幫助!! –