【问题标题】:Python regex, exclude matches in quotesPython正则表达式,排除引号中的匹配项
【发布时间】:2016-02-25 22:26:53
【问题描述】:

我有这个字符串:

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

还有这个搜索括号、逗号和简单运算符的正则表达式。我需要排除双引号内的任何匹配项并能够拆分匹配项。请注意,解决方案仍必须在字符串的其余部分中搜索括号、逗号和运算符。 当前版本的正则表达式是:

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'']

但我需要它来排除引号中的数量,所以匹配应该是:

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'']

【问题讨论】:

  • 使用正则表达式很难确定什么是“内部”引号。您最好的选择可能是使用正则表达式在预处理步骤中连续删除引号内的所有内容,但即使这样嵌套引号也可能会造成问题。
  • 在这种情况下不要尝试使用re.split,尝试为re.findall构建一个模式,这样更简单高效。
  • 如果它在嵌套引号上中断也没关系。

标签: python regex


【解决方案1】:

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

【讨论】:

  • 但是我真的不能对它进行拆分
  • @user1387717 哦,您需要保留引用的字符串作为标记吗?对不起,我错过了。那么你可能需要finditer。我将编辑答案。
  • 标识符似乎不包含数字?为什么这适用于我的示例?
  • @user1387717 我只是在演示一种方法,我相信您可以轻松实现。您可以轻松修改IDENTIFIER 的定义以包含数字。如果您有更多的运算符等,您可以修改OPERATOR 的定义。您当然比我更了解您的需求(数字都是整数吗?以指数表示法?)。
猜你喜欢
  • 2010-11-16
  • 1970-01-01
  • 2022-12-11
  • 2018-11-13
  • 1970-01-01
  • 1970-01-01
  • 2022-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多