Erlang正则表达式匹配中文字符

4
TL;DR:(简而言之):
25> re:run("йцу.asd", xmerl_regexp:sh_to_awk("*.*"), [{capture, none}]). 
** exception error: bad argument
     in function  re:run/3
        called as re:run([1081,1094,1091,46,97,115,100],
                         "^(.*\\..*)$",
                         [{capture,none}])

如何使这个工作?'йцу'是不属于拉丁字符集的字符,显然;有没有一种方法告诉re模块或整个系统使用不同的字符集来运行“字符串”? 原始问题(仅供记录): 在第16章中,有一个关于从mp3文件中读取标签的示例。它很好用。但是,提供的模块lib_find中似乎存在一些bug,其中有一个函数用于在路径中搜索匹配的文件。这是有效的调用:
61> lib_find:files("../..", "*.mp3", true).   
["../../early/files/Veronique.mp3"]

并且这个调用失败:

62> lib_find:files("../../..", "*.mp3", true).
** exception error: bad argument
     in function  re:run/3
        called as re:run([46,46,47,46,46,47,46,46,47,46,107,101,114,108,47,98,117,
                          105,108,100,115,47,50,48,46,49,47,111|...],
                         "^(.*\\.mp3)$",
                         [{capture,none}])
     in call from lib_find:find_files/6 (lib_find.erl, line 29)
     in call from lib_find:find_files/6 (lib_find.erl, line 39)
     in call from lib_find:files/3 (lib_find.erl, line 17)

具有讽刺意味的是,调查结果发现了Erlang自己安装的问题所在:

.kerl/builds/20.1/otp_src_20.1/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴

好吧,这似乎意味着Erlang使用了更为严格的默认字符集,其中不包括汉字。有哪些选择?显然,我可以忽略它并继续学习,但我觉得我可以从中学到更多 =)例如,我在哪里/如何修复默认字符集?我有点惊讶它默认使用的不是UTF8 - 所以也许我走错了路线?

谢谢!

1个回答

4

TL;DR:

如果将正则表达式模式放入unicode模式并使用unicode选项,则可以访问UTF-8 regexs。(请注意,下面介绍的字符串"^(.*\\..*)$"是对xmerl_regexp:sh_to_awk/1调用的结果。)

1> re:run("なにこれ.txt", "^(.*\\..*)$").
** exception error: bad argument
     in function  re:run/2
        called as re:run([12394,12395,12371,12428,46,116,120,116],"^(.*\\..*)$")
2> re:run("なにこれ.txt", "^(.*\\..*)$", [unicode]).
{match,[{0,16},{0,16}]}

并以你的确切示例为例:

11> re:run("йцу.asd", "^(.*\\..*)$", [unicode, {capture, none}]).       
match

或者

12> {ok, Pattern} = re:compile("^(.*\\..*)$", [unicode]).
{ok,{re_pattern,1,1,0,
                <<69,82,67,80,87,0,0,0,16,8,0,0,65,0,0,0,255,255,255,
                  255,255,255,...>>}}
13> re:run("йцу.asd", Pattern, [{capture, none}]).               
match
re文档非常长且详细,这是因为正则表达式本质上是一个复杂的主题。您可以在re:compile/2文档中找到编译后的regex选项,在re:run/3文档中找到运行选项。 讨论 Erlang已经确定了一个想法,即字符串,尽管仍然是代码点列表,但它们在任何地方都是UTF-8格式的。由于我在日本工作并经常处理这些问题,这给了我很大的帮助,因为我可以停止使用以前需要的约一半的转换库(耶!),但对于string模块的用户来说,情况有点复杂,因为许多操作现在根据略微不同的假设执行(即使字符串是一组图形簇的深度列表,只要这些簇存在于列表的第一级中,则仍然认为该字符串是“平面”的)。
不幸的是,编码不是很容易处理的事情,而UTF-8一旦脱离了最常见的表示形式,就变得一点也不简单--所以这方面仍在不断改进。不过,我可以很自信地告诉您,在阅读unicode、regex和string文档后,使用二进制、字符串、深度列表和io_data()形式处理UTF-8数据(无论是文件名、文件数据、网络数据还是来自WX或Web表单的用户输入),都能按预期工作。
但是,当然,这需要熟悉很多东西。99%的时间,如果您将从外部解码的所有内容都指定为UTF-8,并使用unicode:characters_to_list/1unicode:characters_to_binary/1,并在每个地方将二进制字符串指定为utf8二进制类型,那么一切都会按预期工作。
3> UnicodeBin = <<"この文書はUTF-8です。"/utf8>>.
<<227,129,147,227,129,174,230,150,135,230,155,184,227,129,
  175,85,84,70,45,56,227,129,167,227,129,153,227,128,130>>
4> UnicodeString = unicode:characters_to_list(UnicodeBin).  
[12371,12398,25991,26360,12399,85,84,70,45,56,12391,12377,
 12290]
5> io:format("~ts~n", [UnicodeString]).
この文書はUTF-8です。
ok
6> re:run(UnicodeString, "UTF-8", [unicode]).
{match,[{15,5}]}
7> re:run(UnicodeBin, "UTF-8", [unicode]).   
{match,[{15,5}]}
8> unicode:characters_to_binary(UnicodeString).
<<227,129,147,227,129,174,230,150,135,230,155,184,227,129,
  175,85,84,70,45,56,227,129,167,227,129,153,227,128,130>>
9> unicode:characters_to_binary(UnicodeBin).   
<<227,129,147,227,129,174,230,150,135,230,155,184,227,129,
  175,85,84,70,45,56,227,129,167,227,129,153,227,128,130>>

哦,兄弟,一开始我对二进制字符串感到惊讶 - <<"咦,这是干嘛用的,不能直接用字符串吗">> ... 但是当我想到“东西”只是一个虚假的字符串,而二进制则是真实的时候,一切都变得合乎情理了。 - alexakarpov
1
@alexakarpov,“二进制文件诚实”有点虚假(二进制表示意味着上面的“匹配”与第15个字节匹配,但不是第15个词元),匹配“字符”也是虚假的,因为1个字符并不意味着1个词元。词元才是唯一的真相,这就是为什么这会变得如此混乱的一部分(因为没有人想使用4个字节来表示一个[A-Z] ASCII字符!)。所以我们有了词元,它们可能是单个代码点或簇或混合物!啊!但这比任何其他选择都要好,所以我们被困住了。 - zxq9

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接