2016-02-25 51 views
0

我有这个字符串:Python的正则表达式,排除引号比赛

s = MY_FUNC(AVG, WFC US EQUITY, WFC US EQUITY, ">+3%", 1,1,7) 

而这正则表达式,搜索括号,逗号和简单的操作符。我需要排除双引号内的任何匹配项,并能够在匹配项上进行分割。请注意,解决方案仍然必须在字符串的其余部分搜索parens,逗号和运算符。 当前正则表达式的版本:

tokenize_regex = re.compile(r'([\[\]\(\)\+\-\*/<>=!,])') 

比赛为s是:

Match 1 
1. (
Match 2 
1. , 
Match 3 
1. , 
Match 4 
1. , 
Match 5 
1. > 
Match 6 
1. + 
Match 7 
1. , 
Match 8 
1. , 
Match 9 
1. , 
Match 10 
1. ) 

当我做:

tokens = Formula.tokenize_regex.split(self.formula) 
    print 'tokens: ' + str(tokens) 

它返回:

tokens: [u'MY_FUNC', u'(', u'AVG', u',', u' WFC US EQUITY', u',', u' WFC US EQUITY', u',', u' "', u'>', u'', u'+', u'3%"', u',', u' 1', u',', u'1', u',', u'7', u')', u''] 

但我需要d它排除在报价的数量,所以比赛应该是:

Match 1 
1. (
Match 2 
1. , 
Match 3 
1. , 
Match 4 
1. , 
Match 5 
1. , 
Match 6 
1. , 
Match 7 
1. , 
Match 8 
1. ) 

和令牌应该是:

tokens: [u'MY_FUNC', u'(', u'AVG', u',', u' WFC US EQUITY', u',', u' WFC US EQUITY', u',', u'">+3%"', u',', u' 1', u',', u'1', u',', u'7', u')', u''] 
+0

决定什么是“内部”行情是很难用正则表达式。最好的办法可能是使用正则表达式在预处理步骤中连续删除引号内的所有内容,但即使嵌套引号也可能造成问题。 –

+0

不要在这种情况下尝试使用're.split',尝试为're构建一个模式。findall',它更简单,更高效。 –

+0

没关系,如果它嵌套引号中断。 – user1387717

回答

0

re.split不是一个干净的方式做标记化。在re的文档中有一个recipe,它可以更好地为您服务。基本上,你首先为每个词法类型编写一个正则表达式。例如:

lexical_types = [ 
    ('QUOTED_CONTENT', r'"[^"]*?"'), 
    ('PAREN', r'[()]'), 
    ('OPERATOR', r'[-+<>]'), 
    ('COMMA', r','), 
    ('IDENTIFIER', r'[A-Z_][ A-Z_]*'), # our identifier can have spaces in it 
    # ... 
] 

然后你做一个高手的正则表达式了这些:

groups = ('(?P<{}>{})'.format(ltype, regex) for ltype, regex in lexical_types) 
tokenizer = re.compile('|'.join(groups)) 

然后,你将要记号化,以tokenizer.finditer字符串:

s = 'MY_FUNC(AVG, WFC US EQUITY, WFC US EQUITY, ">+3%", 1,1,7)' 
token_iter = tokenizer.finditer(s) # an iterator 

现在,如果你迭代通过token_iter,你将得到一串匹配对象,它包含你可能想要知道的关于字符串的所有信息(词法上,就是这样)。你可能想要做的是根据它的词法类型来处理每个匹配对象。为了演示,让我们打印出来的词汇类型,匹配的字符串,字符串相匹配的位置:

for token in token_iter: 
    ltype = token.lastgroup # lexical type of the token 
    print(ltype, token.group(ltype), token.span(ltype), sep=' ') 

输出

IDENTIFIER MY_FUNC (0, 7) 
PAREN ( (7, 8) 
IDENTIFIER AVG (8, 11) 
COMMA , (11, 12) 
IDENTIFIER WFC US EQUITY (13, 26) 
COMMA , (26, 27) 
IDENTIFIER WFC US EQUITY (28, 41) 
COMMA , (41, 42) 
QUOTED_CONTENT ">+3%" (43, 49) 
COMMA , (49, 50) 
COMMA , (52, 53) 
COMMA , (54, 55) 
PAREN ) (56, 57) 

注:编译主正则表达式时,你必须确保优先级较高的模式出现在优先级较低的模式之前。所以引用应该放在一切之前。由两个字符组成的操作符(如!=)应在由一个字符组成的那些字符之前。

而且这种格局将处理单引号和双引号:

r"""(?:'[^']*?'|"[^"]*?")""" # grouped for readability 
+0

但后来我真的不能在它上面分割 – user1387717

+0

@ user1387717哦,您需要*将引用的字符串保存为标记吗?对不起,我错过了。那么你可能需要'finditer'。我将编辑答案。 – gil

+0

标识符似乎没有包含数字?为什么这对我的例子有效? – user1387717