Python 字符串清理

2 投票
5 回答
1332 浏览
提问于 2025-04-17 03:48

我正在用PyQT写一个程序,这个程序需要处理一些杂乱的字符串并把它们整理干净。输入的字符串可能会非常多样化。比如,我想把这些字符串:

"Seven_Pounds_(BDrip_1080p_ENG-ITA-GER)_Multisub_x264_bluray_.mkv",  
"The_Birds_1963_HDTV_XvidHD_720p-NPW.avi",  
"1892.XVID.AC3.HD.120_min.avi"  

变成:
"七磅",
"鸟类",
"1892"

我考虑过用正则表达式来处理这些字符串,但我觉得这种方法在处理最后一个例子时可能会失败。程序Media Gerbil使用了google diff-match-patch算法来进行字符串清理。这似乎是个更好的选择,但我不太确定怎么实现它。
有没有其他更有效的方法可以在Python/PyQt中清理字符串,还是说正则表达式或者diff-match-patch是最好的选择呢?

5 个回答

2

其实我之前也做过这个...你基本上需要按照一系列步骤来操作。

  • 先去掉方括号 []、圆括号 () 或大括号 {} 里的内容。
  • 然后去掉文件的扩展名。
  • 接下来用空格、点、短横线和下划线来分割字符串。

在你的情况下,你会得到:

Seven Pounds Multisub x264 bluray
The Birds 1963 HDTV XvidHD 720p NPW
1892 XVID AC3 HD 120 min

现在你基本上需要保持一个要从列表中删除的单词清单。在这个例子中,明显的词有 x264、Multisub、bluray、HDTV、XvidHD、Xvid、HD、720p、1040p、AC3。记得这里要不区分大小写地比较。

注意,这个清单会随着你处理的内容而手动增加,这样你就会得到:

Seven Pounds
The Birds 1963
1892 120 min

这大概就是你能得到的半自动化系统的效果了。上面的方法会告诉你去掉那些不在开头的数字,但我想说这样会搞乱像“玩具总动员2”这样的标题。

在我的情况下,我做了上述处理,然后试着找出哪些目录模式适合归档。接着我用一个基于 curses 的界面,让我可以滚动浏览并手动修正脚本的结论(包括重命名)。

补充一下:再想想,我的脚本其实假设可以安全地去掉第二组数字(以及之后的所有内容)。不过这些都是经验法则,你肯定会遇到例外情况。如果加上这一步,就能把最后一个例子的标题改成 1892

2

从diff-match-patch的功能来看,match这个部分最接近你说的内容,但我觉得这可能不是最好的解决方案,因为match似乎是想找特定的模式(而不是正则表达式的规则)?

我觉得你可能需要定义一系列的正则表达式规则,比如把下划线当作单词之间的空格,任何非[a-zA-Z0-9_]+的字符可能表示标题的结束。你至少得假设你的标题是从字符串的开头开始的,然后匹配模式直到遇到一个“非单词”字符。

也许可以这样做?

rx = re.compile(r'([a-zA-Z\d_]+[a-zA-Z\d])[_.]?')

但不幸的是,正如其他回答中提到的,确实没有办法处理像“鸟类 1963”这样的标题。我认为解决方案是结合假设标题应该从哪里开始和可能结束,以及有一个常见标签的列表来去掉一些不必要的部分。

编辑 - 想到了更多的信息

也许当你尽可能缩小潜在标题的范围后,你可以再用google的diff-match-patch去对比一下imdb.com的API搜索,找到最接近真实标题的匹配。

2

根据你的例子:

import re

a="The_Birds_1963_HDTV_XvidHD_720p-NPW.avi"
b="Seven_Pounds_(BDrip_1080p_ENG-ITA-GER)_Multisub_x264_bluray_.mkv"
c="1892.XVID.AC3.HD.120_min.avi"

def cleanit(str):
    result = []
    l = re.split('[_.]',str)
    flag = 0
    if re.match('^[a-zA-z]+',l[0]):
        flag = 1
    elif re.match('^[0-9]+',l[0]):
        flag = 2

    if flag == 1:
        for x in l:
            if not re.match('^[a-zA-Z]+',x):
                break;
            result.append(x) 
        return " ".join(result)

    if flag == 2:
        for x in l:
            if not re.match('^[0-9]+',x):
                break;
            result.append(x) 
        return " ".join(result)

if __name__ == '__main__':
    print cleanit(a)
    print cleanit(b)
    print cleanit(c)

将会输出:

kent$  python cleanit.py
The Birds
Seven Pounds
1892

撰写回答