【问题标题】:Parameterised regular expression in PythonPython中的参数化正则表达式
【发布时间】:2010-10-07 23:38:09
【问题描述】:

在 Python 中,有没有更好的方法来将字符串参数化为正则表达式,而不是像这样手动进行:

test = 'flobalob'
names = ['a', 'b', 'c']
for name in names:
    regexp = "%s" % (name)
    print regexp, re.search(regexp, test)

这个点头的例子试图依次匹配每个名字。我知道有更好的方法可以做到这一点,但它只是一个简单的例子来说明这一点。


答案似乎是否定的,没有真正的选择。在 python 中参数化正则表达式的最佳方法是如上所述或使用诸如str.format() 之类的衍生物。我尝试编写一个通用问题,而不是 'fix ma codez, kthxbye'。对于那些仍然感兴趣的人,我在这里充实了一个更接近我需要的示例:

for diskfilename in os.listdir(''):
    filenames = ['bob.txt', 'fred.txt', 'paul.txt']
    for filename in filenames:
        name, ext = filename.split('.')
        regexp = "%s.*\.%s" % (name, ext)
        m = re.search(regexp, diskfilename)
        if m:
          print diskfilename, regexp, re.search(regexp, diskfilename)
          # ...

我正在尝试根据文件名确定文件的“类型”,格式为<filename>_<date>.<extension>。在我的真实代码中,filenames 数组是一个字典,包含一个找到匹配项后调用的函数。

我考虑过的其他方式:

  • 在数组中有一个正则表达式。我已经有一个没有任何正则表达式魔法的文件名数组,所以我不愿意这样做。我在我的代码中的其他地方做了这个,它一团糟(尽管在那里是必要的)。

  • 仅匹配文件名的开头。这可行,但会与文件的 .bak 副本等中断。在某些时候,我可能想要提取日期来自文件名,所以无论如何都需要使用正则表达式。


感谢您的回复,建议使用正则表达式的替代方法来实现相同的最终结果。我对现在和未来的正则表达式参数化更感兴趣。我从来没有遇到过 fnmatch,所以从长远来看它都是有用的。

【问题讨论】:

  • 如果您就具体案例提出问题,您可能会得到更好的答案。
  • 在知道参数化正则表达式之后,我更多的是比修复我的作业,kthxbye。见上文。
  • 我只有一个你可能已经知道的评论,但我想确定一下——当一遍又一遍地使用相同的正则表达式时,如果你先编译它们,你会看到更好的性能: p = re.compile(s) 您的示例(以及响应中的其他示例)不这样做。
  • 公平点,但请参阅stackoverflow.com/questions/452104/…

标签: python regex


【解决方案1】:

好吧,当您从字符串构建正则表达式时,我看不到其他方法。但是你可以用字典参数化字符串本身

d = {'bar': 'a', 'foo': 'b'}
regexp = '%(foo)s|%(bar)s' % d

或者,根据问题,您可以使用列表推导:

vlist = ['a', 'b', 'c']
regexp = '|'.join([s for s in vlist])

编辑: Mat 澄清了他的问题,这使事情变得不同,上面提到的完全无关紧要。

我可能会采用这样的方法:

filename = 'bob_20090216.txt'

regexps = {'bob': 'bob_[0-9]+.txt',
           'fred': 'fred_[0-9]+.txt',
           'paul': 'paul_[0-9]+.txt'}

for filetype, regexp in regexps.items():
    m = re.match(regexp, filename)
    if m != None:
        print '%s is of type %s' % (filename, filetype)

【讨论】:

  • +1 我检查了文档以确保没有办法做到这一点(除了按照您所说的对字符串进行参数化)。而且我认为 Python 不需要。
  • @paprika:我已经澄清了这个例子,以便更好地解释我的意思。 @David:我自己在文档中找不到任何东西,但假设它会很常见,以至于有一些东西 - 也许有东西以这种方式使用字符串。
  • if m: 在这种情况下就足够了。一般来说if obj is not Noneif obj != None好。
  • @J.F. Sebastian:确实,“如果 m: ...”就足够了。我不知何故坚持了这一点,因为我学会了避免使用简短的“if v: ...”来检查布尔值的真/假(这是一个完全不同的故事)。您能否详细说明为什么“不是”更好?仅仅因为可读性还是其他什么?
  • is 检查对象身份(内存中的对象地址),因此效率很高,但我使用这种形式纯粹是为了便于阅读。
【解决方案2】:

可能是globfnmatch 模块对你有帮助吗?

【讨论】:

    【解决方案3】:
    import fnmatch, os
    
    filenames = ['bob.txt', 'fred.txt', 'paul.txt']
    
                      # 'b.txt.b' -> 'b.txt*.b'
    filepatterns = ((f, '*'.join(os.path.splitext(f))) for f in filenames) 
    diskfilenames = filter(os.path.isfile, os.listdir(''))
    pattern2filenames = dict((fn, fnmatch.filter(diskfilenames, pat))
                             for fn, pat in filepatterns)
    
    print pattern2filenames
    

    输出:

    {'bob.txt': ['bob20090217.txt'], 'paul.txt': [], 'fred.txt': []}
    

    您问题的先前版本的答案如下:


    我不明白您更新的问题,但 filename.startswith(prefix) 在您的具体情况下可能就足够了。

    在您更新问题后,下面的旧答案不再相关。


    1. 如果您想逐字匹配name,请使用re.escape(name)

    2. 任何可用于字符串参数化的工具都适用于此。例如:

      import string
      print string.Template("$a $b").substitute(a=1, b="B")
      # 1 B
      

      或者在 Python 2.6+ 中使用str.format()

      print "{0.imag}".format(1j+2)
      # 1.0
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-06
      • 1970-01-01
      • 1970-01-01
      • 2010-09-12
      相关资源
      最近更新 更多