【问题标题】:list comprehension using regex conditional使用正则表达式条件列表理解
【发布时间】:2014-04-18 18:41:17
【问题描述】:

我有一个字符串列表。 如果这些字符串中的任何一个有 4 位数的年份,我想在年底截断字符串。 否则我不理会这些字符串。

我尝试使用:

    for x in my_strings:   
      m=re.search("\D\d\d\d\d\D",x)  
      if m: x=x[:m.end()]  

我也试过了:

my_strings=[x[:re.search("\D\d\d\d\d\D",x).end()] if re.search("\D\d\d\d\d\D",x) for x in my_strings]  

这些都不起作用。

你能告诉我我做错了什么吗?

【问题讨论】:

  • 对于不懂 Python 但懂 REGEX 的人来说,示例输入/输出会更容易理解。

标签: python regex list list-comprehension conditional-statements


【解决方案1】:

这样的事情似乎适用于琐碎的数据:

>>> regex = re.compile(r'^(.*(?<=\D)\d{4}(?=\D))(.*)')                         
>>> strings = ['foo', 'bar', 'baz', 'foo 1999', 'foo 1999 never see this', 'bar 2010 n 2015', 'bar 20156 see this']
>>> [regex.sub(r'\1', s) for s in strings]
['foo', 'bar', 'baz', 'foo 1999', 'foo 1999', 'bar 2010', 'bar 20156 see this']

【讨论】:

    【解决方案2】:

    看起来您对结果字符串的唯一限制是end(),因此您应该改用re.match(),并将您的正则表达式修改为:

    my_expr = r".*?\D\d{4}\D"
    

    然后,在您的代码中,执行:

    regex = re.compile(my_expr)
    my_new_strings = []
    for string in my_strings:
        match = regex.match(string)
        if match:
            my_new_strings.append(match.group())
        else:
            my_new_strings.append(string)
    

    或者作为一个列表理解

    regex = re.compile(my_expr)
    matches = ((regex.match(string), string) for string in my_strings)
    my_new_strings = [match.group() if match else string for match, string in matches]
    

    或者,您可以使用re.sub:

    regex = re.compile(r'(\D\d{4})\D')
    new_strings = [regex.sub(r'\1', string) for string in my_strings]
    

    【讨论】:

    • 为什么结果的界限对于确定是使用 re.match() 还是 re.search() 很重要?另外——你会推荐你的列表理解代码作为在列表理解中使用条件正则表达式的通用模板吗?这种 Code Pattern 有什么缺点?
    • @mpacer: re.match("foo") 等价于re.search("^foo")match() 总是从字符串的开头开始。
    • @mpacer:我认为最简洁的模式是我在底部添加的re.sub 模式。
    【解决方案3】:

    我不完全确定你的用例,但下面的代码可以给你一些提示:

    import re
    
    my_strings = ['abcd', 'ab12cd34', 'ab1234', 'ab1234cd', '1234cd', '123cd1234cd']
    
    for index, string in enumerate(my_strings):
        match = re.search('\d{4}', string)
        if match:
            my_strings[index] = string[0:match.end()]
    
    print my_strings
    
    # ['abcd', 'ab12cd34', 'ab1234', 'ab1234', '1234', '123cd1234']
    

    【讨论】:

    • 这不会保留 \D 行为(尽管添加它不会太难)。
    【解决方案4】:

    您实际上非常接近列表理解,但您的语法不正确 - 您需要将第一个表达式设为“条件表达式”,也就是 x if &lt;boolean&gt; else y

    [x[:re.search("\D\d\d\d\d\D",x).end()] if re.search("\D\d\d\d\d\D",x) else x for x in my_strings]
    

    显然这很难看/难以阅读。有几种更好的方法可以将字符串拆分为 4 位数的年份。如:

    [re.split(r'(?<=\D\d{4})\D', x)[0] for x in my_strings]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-02
      • 1970-01-01
      • 1970-01-01
      • 2016-09-19
      • 2018-10-17
      • 2017-11-25
      相关资源
      最近更新 更多