避免正则表达式[python]

时间:2010-08-30 01:57:40

标签: python regex

我想知道避免正则表达式是否是一个好主意。

实际上我在任何情况下都避免使用它,有些人一直在给我建议,我不应该避免它,因为如果你知道每件事的意义:

  
    

[]'|' \ A \ B \ d \ D \ W \ W \ S \ Z $ *? ......

  

它很容易阅读,对吗?但我喜欢避免正则表达式,我会有一个更易读的代码。

当它变大时会变得更难以辨认,例如:validators.py

email_re = re.compile(
    r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' #     quoted-string
    r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE)  # domain

所以,我想知道一个不能避免正则表达式的理由吗?

6 个答案:

答案 0 :(得分:18)

不,不要避免使用正则表达式。它们实际上是一个非常漂亮的小工具,如果您明智地使用它们,它们将为您节省大量工作。

做什么需要避免的是尝试将它用于所有事情,这种不适似乎会使那些新的正则表达式变得更加温和,而不是那么迷恋:-)

例如,使用它来验证电子邮件地址。验证电子邮件地址的方式是向其发送电子邮件,其中包含接收者必须单击以完成“交易”的链接。

有数十亿有效的电子邮件地址(根据RFC),其背后没有物理电子邮件接收器。 唯一方式确定是否有接收方是发送电子邮件并等待证明其收到并采取行动。

如果我发现自己正在编写一个超过60个字符的正则表达式,我会退一步看看是否有更易读的方法。同样地,如果我写一个正则表达式并在一周后回来并且无法立即识别它的作用,我会考虑更换它。这个特别的段落当然包含了我的观点,但他们对我很有帮助: - )

答案 1 :(得分:6)

正则表达式是一种工具。它们非常适合某些任务而不适合其他任务。像任何工具一样,当它们是适合工作的工具时使用它们。不要只是避开它们,因为有人说它们很糟糕。学习如何使用它们然后你可以自己决定,而不是依赖别人的教条。

答案 2 :(得分:2)

如果您选择使用更通用的解析方法,例如pyparsingPLY,您将永远不会需要正则表达式(它只能匹配一小部分正则表达式)与这种通用解析器匹配的语言)。然而,PLY中的词法分析器通常围绕正则表达式构建(这是词法分析器需要的完美匹配!),因此您可能必须避免使用它(以及强大的工具,如{{} 1}}当任何“普通”用户能够通过简单地传递正则表达式对象作为选择器来继续使用和享受它时,因为BeautifulSoup完全支持它,并且必须重新编码许多这样的现有解析器使用您选择的通用解析包。

当然,在更简单,高度优化和简洁的工具将是一个完美的解决方案的情况下,通过使用极其通用的工具,性能可能会受到很大影响 - 并且代码的大小可能会“爆炸”到非常大的许多常见病例。但是如果你不介意有两倍大的程序和两倍慢的程序,并且决心不惜一切代价避免使用正则表达式,你可以这样做。

另一方面,如果您的主要关注点是可读性(这也是一个可以理解且值得称赞的问题),那么BeautifulSoup选项允许在RE的模式中充分利用空白和注释,可以真正实现在没有删除任何 RE的优势的情况下为这个目标创造奇迹(除了稀释有时过于简洁;-)。你当然希望保留至少一个通用的解析系统(当然,不是为了完成他们错误的任务,而是让很多人不幸做!) - - 但是在很多情况下(例如,充分利用re.VERBOSE和许多其他工具可以接受RE作为参数来适当地应用它们),RE的最小命令将很好地为您服务,我认为这是相当的被推荐。

答案 3 :(得分:1)

只是为了进行一些比较,这里我的版本电子邮件格式不是用regexp(带有测试用例)和一个可读的regexp作为替代方案提供给我(虽然在接受后发送电子邮件,这是个好主意):

# -*- coding: utf8 -*- 
import string
print("Valid letters in this computer are: "+string.letters)
import re 
def validateEmail(a): 
    sep=[x for x in a if not (x.isalpha() or 
                              x.isdigit() or 
                              x in r"!#$%&'*+-/=?^_`{|}~]") ] 
    sepjoined=''.join(sep) 
    ## sep joined must be ..@.... form 
    if len(a)>255 or sepjoined.strip('.') != '@': return False 
    end=a 
    for i in sep: 
        part,i,end=end.partition(i) 
        if len(part)<2: return False 
    return len(end)>1 

def emailval(address): 
    pattern = "[\.\w]{2,}[@]\w+[.]\w+" 
    return re.match(pattern, address)

if __name__ == '__main__': 
    emails = [ "test.@web.com","test+john@web.museum", "test+john@web.m", 
               "a@n.dk", "and.bun@webben.de","marjaliisa.hämäläinen@hel.fi", 
               "marja-liisa.hämäläinen@hel.fi", "marjaliisah@hel.",'tony@localhost',
               '1234@23.45','me@somewhere'] 

    print('\n\t'.join(["Valid emails are:"] + 
                      filter(validateEmail,emails)))

    print('\n\t'.join(["Regexp gives wrong answer:"] + 
                       filter(emailval,emails)))

""" Output:
Valid letters in this computer are: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
Valid emails are:
        test+john@web.museum
        and.bun@webben.de
        tony@localhost
        1234@23.45
        me@somewhere
Regexp gives wrong answer:
        test.@web.com
        and.bun@webben.de
        1234@23.45
"""

编辑:从这个古老的代码中清除了正则表达式过滤器功能,为基于更宽松版本的@detly链接编辑。在发送确认电子邮件之前,我已经足够先填写表格。最后将评论中提到的255个字符长度限制检查。

此代码按目的不接受正常的a @ b作为有效的电子邮件地址,但确实接受我@ somewhere。另一件事是它取决于isalpha的回报。所以来自Ideone.com的这个输出还没有接受斯堪的纳维亚语,即使它们现在也是有效的。在我的家用电脑上运行时,会接受这些。即使编码行在那里也是如此。

答案 4 :(得分:0)

(删除了一个声称是“正式”的正则表达式,但事实上在它声称来自的RFC中找不到。)

This正则表达式可能很有趣,因为它试图精确匹配旧版Internet邮件标准中提供的电子邮件地址语法。

答案 5 :(得分:-1)

正则表达式可能是提取/验证电子邮件地址的正确工具......

从原始文本中提取一个或多个电子邮件地址:

import re
pat_e = re.compile(r'(?P<email>[\w.+-]+@(?:[\w-]+\.)+[a-zA-Z]{2,})')
emails = []
for r in pat_e.finditer(text):
  emails.append(r.group('email'))
return emails

查看单个文本是否是有效的电子邮件:

import re
pat_m = re.compile(r'([\w.+-]+@(?:[\w-]+\.)+[a-zA-Z]{2,}$)')
if pat_m.match(text):
  return True
return False