代码之家  ›  专栏  ›  技术社区  ›  Mat

python中的参数化正则表达式

  •  3
  • Mat  · 技术社区  · 16 年前

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

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

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


    答案似乎是否定的,没有真正的选择。在python中对正则表达式进行参数化的最佳方法是如上所述或使用诸如 str.format() . 我试着写一个普通的问题,而不是 '修复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 数组是一个dict,包含一个在找到匹配项后要调用的函数。

    我考虑过的其他方法:

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

    • 仅在文件名开头匹配。 这会有效,但会破坏文件的.bak副本等。在某个时候,我可能希望从文件名中提取日期,因此无论如何都需要使用正则表达式。


    感谢您的回答,建议使用正则表达式的替代方法来获得相同的最终结果。我对现在和将来的正则表达式参数化更感兴趣。我从来没有遇到过 不匹配 从长远来看,这一切都是有用的。

    3 回复  |  直到 15 年前
        1
  •  6
  •   paprika    16 年前

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

    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)
    
        2
  •  2
  •   SilentGhost    16 年前

    可能是 glob fnmatch 模块对您有帮助吗?

        3
  •  2
  •   jfs    16 年前
    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. 使用 re.escape(name) 如果你想匹配 name 字面意思。

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

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

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

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