正则表达式和 unicode

Posted

技术标签:

【中文标题】正则表达式和 unicode【英文标题】:Regex and unicode 【发布时间】:2010-09-06 01:49:52 【问题描述】:

我有一个脚本可以解析电视剧集的文件名(例如 show.name.s01e02.avi),获取剧集名称(来自 www.thetvdb.com API)并自动将它们重命名为更好的名称(显示名称- [01x02].avi)

脚本运行良好,直到您尝试在具有 Unicode 显示名称的文件上使用它(这是我从未真正想过的,因为我拥有的所有文件都是英文的,所以几乎所有文件都属于 @ 987654321@)

如何让正则表达式匹配重音字符等?目前正则表达式的配置部分看起来像..

config['valid_filename_chars'] = """0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@£$%^&*()_+=-[]"'.,<>`~? """
config['valid_filename_chars_regex'] = re.escape(config['valid_filename_chars'])

config['name_parse'] = [
    # foo_[s01]_[e01]
    re.compile('''^([%s]+?)[ \._\-]\[[Ss]([0-9]+?)\]_\[[Ee]([0-9]+?)\]?[^\\/]*$'''% (config['valid_filename_chars_regex'])),
    # foo.1x09*
    re.compile('''^([%s]+?)[ \._\-]\[?([0-9]+)x([0-9]+)[^\\/]*$''' % (config['valid_filename_chars_regex'])),
    # foo.s01.e01, foo.s01_e01
    re.compile('''^([%s]+?)[ \._\-][Ss]([0-9]+)[\.\- ]?[Ee]([0-9]+)[^\\/]*$''' % (config['valid_filename_chars_regex'])),
    # foo.103*
    re.compile('''^([%s]+)[ \._\-]([0-9]1)([0-9]2)[\._ -][^\\/]*$''' % (config['valid_filename_chars_regex'])),
    # foo.0103*
    re.compile('''^([%s]+)[ \._\-]([0-9]2)([0-9]2,3)[\._ -][^\\/]*$''' % (config['valid_filename_chars_regex'])),
]

【问题讨论】:

【参考方案1】:

使用[\u0000-\uFFFF] 的子范围来满足您的需求。

您也可以使用re.UNICODE 编译标志。 The docs 表示如果设置了 UNICODE\w 将匹配字符 [0-9_] 加上 Unicode 字符属性数据库中分类为字母数字的任何内容。

另见http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-05/2560.html

【讨论】:

【参考方案2】:

Python 的 re 模块不支持 \pLetter 或 \X。但是,new regex implementation on PyPI 可以。

【讨论】:

那个模块的\X坏了;他们误解了标准。你不能只使用\PM\pM*,否则你会出错。考虑字符串"\r\r\n\x301A\x301"。 conforming application 为 \X 找到以下 4 个匹配项:1 个 CP U+000D、2 个 CP U+000D U+000A、1 个 CP U+0301 和 2 个 CP U+0041 U+0301。损坏的\PM\pM* 也找到 4 个匹配项,但错误的匹配项:1 个 CP U+000D、1 个 CP U+000D、2 个 CP U+000A U+0301 和 2 个 CP U+0041 U +0301。您必须不要分解 CRLF,也不要在任何 \PGrapheme_Base 代码点上放置标记。 \X 的定义是基于以下内容:regular-expressions.info/unicode.html 看看能不能解决。 最初的字素集群想法在一些事情上有点混乱,所以第一批使用\X 的人最终做错了。当前的 ICU 和 Perl 实现确实做到了,实际上甚至使用了扩展的字形集群定义:尝试perl5.12.0 -le 'printf "%d %v04X\n", length, $_ for "\r\r\n\x301A\x301" =~ /\X/g' 或更高版本以查看改进的答案。 @tchrist:它现在似乎已修复(或从未被破坏)。 python -c'import regex as re; print(re.findall(u"\X", u"\r\r\n\u0301A\u0301"))' 打印预期结果:[u'\r', u'\r\n', u'\u0301', u'A\u0301'] @J.F.Sebastian 我知道它确实得到了修复。我与作者进行了长时间的通信。他很棒。【参考方案3】:

在 Jeffrey Friedl 的 Mastering Regular Expressions(好书)中提到您可以使用 \pLetter 来匹配被视为字母的 unicode 内容。

【讨论】:

\pLetter 在所有正则表达式引擎中不受支持,在 Python 的情况下,默认 re 引擎不支持它。它仅在 regex 包中受支持。【参考方案4】:

\X 似乎在某些语言中可用作通用单词字符,它允许您匹配单个字符而不管它占用多少字节。可能有用。

【讨论】:

以上是关于正则表达式和 unicode的主要内容,如果未能解决你的问题,请参考以下文章

带有 unicode 和标点符号的 Javascript 正则表达式

用 Java 正则表达式匹配(例如)一个 Unicode 字母

Python 和带有 Unicode 的正则表达式

正则表达式入门匹配unicode和其他字符

匹配正则表达式中的 Unicode 字符

正则表达式:去除Unicode