正则表达式和 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 正则表达式