0

我正在尝试使用 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) 部分做任何事情。以上应翻译为:

|(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) 正在被拾取。如果我调整正则表达式,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)))"

4

3 回答 3

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)
于 2013-12-14T18:32:41.590 回答
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)

请注意,我将您更改strdata: str是一个大量使用的内置函数的名称,创建一个具有相同名称的变量是一个非常糟糕的主意。

于 2013-12-14T18:39:15.710 回答
0

您只需要使用单词边界\b

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

print re.sub(r'\bn?char\(([^)]+)\)(?:\s*\+\s*)?', conv, str, re.IGNORECASE)
于 2013-12-14T18:26:21.447 回答