你的语言在实践中对Unicode的支持如何?

7
我正在寻找一种新的编程语言,希望找到一种不需要担心字符集问题和其他烦恼(我对PHP有些不满意)的语言来进行新项目开发。
我觉得Java太啰嗦、杂乱无章,而我不想碰Windows系统。这就只剩下其他所有语言了,除了PHP、C和C++(后两者即使使用ICU库也会出现unicode问题)。
我已经列出了几种编程语言,包括Ruby(喜欢mixin),Python,Lisp和Javascript(node.js)。然而,我在支持Unicode方面存在高度不一致的信息,并且我害怕(由于时间不足...)学习每一种语言,以至于我可以安全地将其排除在外。就我所知,Python 3似乎有这个功能。Ruby 1.9也有。Lisp不一定。Javascript可能有。

语言的支持不仅仅局限于Unicode,但在我看来,当处理本地化时,它往往成为一个主要的障碍。

我也意识到这个问题有些主观。(请不要因为这个理由关闭它:我实际上链接了几个我认为不令人满意的SO线程。) 但是...作为这些语言的用户,它们在实践中对Unicode的支持情况如何?


完全不同意你关于Java的看法。Node.js支持Unicode,不是因为它是一个特定的实现,而是因为作为一种语言的JavaScript本身就支持Unicode(这是ECMAScript标准的一部分),所以在这方面应该很顺畅。如果你在强调字符串支持方面,我觉得你可能没有选择正确的工具来完成工作。 - davin
1
@Davin:我对Java有点抵触...大学里编写Java代码的时候可能让我受到了创伤。是的,我同意Node.js是一个不错的选择,尽管它和它的库相当新。但我仍然很想调查其他选项,因为Node.js(可能错误地)没有给我留下足够成熟/稳定的印象。 - Denis de Bernardy
2
不用担心。唯一喜欢Java的人是那些患有斯德哥尔摩综合症的人。 - ryeguy
@ryeguy:虽然听起来非常可怕,但我确实能在某种程度上理解这一点——对于PHP来说也是如此,我非常清楚为什么我已经有一年没有碰过一行PHP代码了。 - Denis de Bernardy
6个回答

7
Python在3.x版本中的unicode支持实际上并没有发生多大变化。自Python 2.x引入单独的“unicode”类型和编码处理以来,Python的unicode支持基本保持不变。Python 3.x所做的更改是将unicode变为唯一的字符串类型,并将其重命名为“str”,而2.x具有字节串(“str”,“...”)和Unicode字符串(“unicode”,“u ...”),这些字符串经常但并不总是不能完全混合使用(允许它们混合使用是为了使从字节串到Unicode的过渡更容易,但最终证明是一个错误)。总的来说,Python的unicode支持非常好,尽管在Python 2.x中存在错误。有带数字和命名转义的Unicode文本、用于unicode文本中的非ASCII字符的源编码声明、通过“codecs”模块进行自动编解码、许多库中的unicode支持(如正则表达式和DB-API模块)以及内置的unicode数据库。
话虽如此,为了正确处理文本,您仍然需要了解编码。您的程序将以某种编码方式接收字节(无论是从文件、环境变量还是通过其他输入),并且需要以该编码方式进行解释。如果您不知道编码(并且无法从数据中确定,例如在HTML或XML中),则只能将数据处理为字节。如果您知道编码,Python确实允许您以大多数透明的方式处理它。

2
确实,在2.6和3.0之间,Unicode的支持并没有发生太大变化,但重要的是人们是否使用该功能。尽管它很琐碎,但那个小小的“u”前缀阻止了人们使用Unicode字符串,因此必须将其删除。 - dan04
3
u'' 并不是问题所在,当混合使用字节字符串和 Unicode 时隐式转换才是最重要的事情。 - Thomas Wouters
谢谢...你知道是否有一种方法可以配置它使用显式的语言环境/排序规则集(以便字符串比较尊重后者)。例如,在Postgres中,我可以编写:SELECT col1 < col2 COLLATE "de_DE" FROM test; - Denis de Bernardy
Unicode类型本身按照Unicode代码点号进行比较。如果您想要不同(特定的)排序规则,通常的做法是使用PyICU,它包装了IBM的icu库。 - Thomas Wouters

6

Perl对Unicode有着极好的支持。你需要知道如何适当地使用它,但我从未发现任何语言比Perl对Unicode的支持更好,尤其是现在的Perl5.14。


2
真的吗?我本来以为它会这样做,但我不得不问一下,因为这个在SO上的答案让我感到毛骨悚然,几乎是到处都是... :-( - Denis de Bernardy
2
仔细阅读(真的非常仔细)这篇文章:https://dev59.com/_W025IYBdhLWcg3wLizo。当你使用perl/unicode时,必须遵循一些规则。当你遵循这些规则时,你将获得极其强大和完整的Unicode支持,包括字符名称、转换、排序、NFC/NFD等。在我看来,这是任何其他语言都无法比拟的。 - clt60
2
是的,那就是我链接的帖子,这也是我的全部观点。在提问之前,我深入阅读了它,但最终决定不将其作为选项提及。我认真考虑过,但被采纳的答案让它听起来像是一件非常麻烦的事情(相比之下,Postgres“只是工作”)。不过,我可能误解了... - Denis de Bernardy
1
在提到的答案中,tchrist 指出了许多来自 Unicode 本身的问题。许多语言都无法处理这些问题。Perl 可以,但代价就在这里。需要知道如何正确使用它。有些语言根本不记录这些细节,用户认为支持还好,后来才发现真相。例如,如何处理 NFD 文件名转换的语言?只需尝试在其他语言中从 tchist 的答案中提出具体问题 - 您就会看到自己的情况。;) - clt60
1
欢迎来到 Perl :) 一旦入门,你就再也离不开了。:) :) - clt60
显示剩余9条评论

3

Racket(属于Lisp/Scheme阵营)支持良好的Unicode。Racket区分字符字符串(写为"abc")和字节字符串(写为#"abc")。字符字符串由Unicode字符组成,并具有所有预期的Unicode感知字符串操作(比较、大小写转换等)。默认情况下,Racket使用UTF-8进行字符字符串I/O(包括源文件的编码),但它也支持转换到其他编码和从其他编码转换。GUI工具包与Unicode一起工作。正则表达式也是如此。


谢谢...你知道是否有一种方法可以配置它使用显式的语言环境/排序规则集(以便字符串比较尊重后者)。例如,在Postgres中,我可以编写:SELECT col1 < col2 COLLATE "de_DE" FROM test; - Denis de Bernardy
@Denis,是的,有区域敏感的比较函数和设置区域的方法。请参见http://docs.racket-lang.org/reference/encodings.html#(tech._locale)。 - Ryan Culpepper

2

根据我的个人经验,Ruby 1.9.2 内部对 Unicode 的处理相当不错,除了一些奇怪的地方,比如 String 类的 upcase/downcase/capitalize 方法。因此我需要为我的所有 Rails 应用程序覆盖这些方法。


2
“我必须为我所有的Rails应用程序覆盖它们。”--这难道不意味着,相反,它比这一系列文章所建议的要差得多吗? - Denis de Bernardy
不确定“alot”是什么意思,只有3个方法而已。我不知道他们为什么还没有为它们添加Unicode支持。 - Jake Jones
2
Jörg W Mittag解释了这个问题。 - steenslag
Steenslag在Ruby方面发表了自己的答案,解释了你提到的三个异常。 - Denis de Bernardy
@daekrist:ICU和iconv在这方面做得相当不错。例如,在Postgres中:select upper('jörg'); -- JÖRG - Denis de Bernardy
显示剩余5条评论

2

Lisp语言对Unicode有很强的支持。所有现代流行的Lisp方言(SBCL、Clozure CL、clisp)都使用UTF-32/UCS-4作为字符串编码,并支持UTF-8作为外部格式。


谢谢。你知道是否有一种方法来配置它以使用显式的语言环境/排序规则集(以便字符串比较尊重后者)。例如,在Postgres中,我可以编写:SELECT col1 < col2 COLLATE "de_DE" FROM test; - Denis de Bernardy

1

Ruby 示例:

# encoding: UTF-8
puts RUBY_VERSION  # => 1.9.2

def Σ(arr)
  arr.inject(:+)
end

Π = Math::PI
str = "abc日本def"

puts Σ [4,6,8,3]  # => 21
puts Π            # => 3.141592653589793
puts str.scan(/\p{Han}+/)  # => 日本
p Encoding.name_list # not just utf8
#["ASCII-8BIT", "UTF-8", "US-ASCII", "Big5", "Big5-HKSCS", "Big5-UAO", "CP949", "Emacs-Mule", "EUC-JP", "EUC-KR", "EUC-TW", "GB18030", "GBK", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-8859-10", "ISO-8859-11", "ISO-8859-13", "ISO-8859-14", "ISO-8859-15", "ISO-8859-16", "KOI8-R", "KOI8-U", "Shift_JIS", "UTF-16BE", "UTF-16LE", "UTF-32BE", "UTF-32LE", "Windows-1251", "BINARY", "IBM437", "CP437", "IBM737", "CP737", "IBM775", "CP775", "CP850", "IBM850", "IBM852", "CP852", "IBM855", "CP855", "IBM857", "CP857", "IBM860", "CP860", "IBM861", "CP861", "IBM862", "CP862", "IBM863", "CP863", "IBM864", "CP864", "IBM865", "CP865", "IBM866", "CP866", "IBM869", "CP869", "Windows-1258", "CP1258", "GB1988", "macCentEuro", "macCroatian", "macCyrillic", "macGreek", "macIceland", "macRoman", "macRomania", "macThai", "macTurkish", "macUkraine", "CP950", "CP951", "stateless-ISO-2022-JP", "eucJP", "eucJP-ms", "euc-jp-ms", "CP51932", "eucKR", "eucTW", "GB2312", "EUC-CN", "eucCN", "GB12345", "CP936", "ISO-2022-JP", "ISO2022-JP", "ISO-2022-JP-2", "ISO2022-JP2", "CP50220", "CP50221", "ISO8859-1", "Windows-1252", "CP1252", "ISO8859-2", "Windows-1250", "CP1250", "ISO8859-3", "ISO8859-4", "ISO8859-5", "ISO8859-6", "Windows-1256", "CP1256", "ISO8859-7", "Windows-1253", "CP1253", "ISO8859-8", "Windows-1255", "CP1255", "ISO8859-9", "Windows-1254", "CP1254", "ISO8859-10", "ISO8859-11", "TIS-620", "Windows-874", "CP874", "ISO8859-13", "Windows-1257", "CP1257", "ISO8859-14", "ISO8859-15", "ISO8859-16", "CP878", "SJIS", "Windows-31J", "CP932", "csWindows31J", "MacJapanese", "MacJapan", "ASCII", "ANSI_X3.4-1968", "646", "UTF-7", "CP65000", "CP65001", "UTF8-MAC", "UTF-8-MAC", "UTF-8-HFS", "UCS-2BE", "UCS-4BE", "UCS-4LE", "CP1251", "UTF8-DoCoMo", "SJIS-DoCoMo", "UTF8-KDDI", "SJIS-KDDI", "ISO-2022-JP-KDDI", "stateless-ISO-2022-JP-KDDI", "UTF8-SoftBank", "SJIS-SoftBank", "locale", "external", "filesystem", "internal"]

实际上,非ASCII字符不支持大写,这是有原因的。


好的...所以如果我理解正确,如str.len()、str.sub()等都是多字节感知的;只有像upper()/lower()这样的区域感知功能需要注意吗?如果是这样,是否有任何方式可以让Ruby知道在应用程序级别使用哪个区域设置/音译规则? - Denis de Bernardy
大小写转换(upcase、swapcase、capitalize等)仅在ASCII区域内有效,因此“jörg”.upcase为“JöRG”。除此之外,我不知道还有任何特定于语言的内容。 - steenslag
没错。但是有没有一种方法可以配置它以某种显式的区域设置/排序规则使用(例如,使字符串比较遵循排序规则)。例如,在Postgres中,我可以编写:SELECT col1 < col2 COLLATE "de_DE" FROM test; - Denis de Bernardy
自 Ruby 2.4 开始,String#downcase 等方法接受一个可选参数,默认为完整的 Unicode 大小写映射。 - steenslag

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