erlang 字符串的奇怪行为:长度函数

cgfeq70w  于 2023-03-11  发布在  Erlang
关注(0)|答案(2)|浏览(200)

为什么性格的存在会导致失败。

> Bin = <<"â Hello">>.
> string:length(Bin).

** exception error: bad argument: <<"â Hello">>
     in function  string:length_1/2 (string.erl, line 557)

然而,如果将其转换为List,则工作正常。

> Str = binary_to_list(Bin).
> string:length(Str).
  7
qojgxg4l

qojgxg4l1#

string:length()的参数可以是整数列表(其中整数介于0...1114111之间),也可以是二进制数,其中整数簇必须形成UTF-8字符。
表示字符âsmall letter a with circumflex)的方法有很多种,其中两种是:
1.拉丁1整数代码226

  1. UTF-8表示法:195, 162(或十六进制:(第三条第2款)
5> <<195, 162>>.
 <<"â"/utf8>>

当您键入二进制时,您的键盘可能输入了“带抑扬符的小写字母a”的拉丁语-1代码,而226不是任何有效的UTF-8整数代码的开头,因此Erlang给了您一个bad argument错误。
接下来,为什么将二进制转换为列表可以工作?在erlang中,双引号是创建整数列表的快捷方式:

6> "abc" =:= [97,98,99].  (exactly equal)
true

每当你在erlang中看到双引号时,你应该会想:“这是一个列表。”该规则的一个例外是当您在二进制文件中使用双引号时:创建一系列以逗号分隔的整数,而不是创建一个列表:

8> <<"abc", 0>>.
<<97,98,99,0>>

添加一个0是一个技巧,它迫使shell向你展示你真正拥有的东西,或者,你可以告诉erlang不要试图用双引号来愚弄你,而是向你展示真相:

18> shell:strings(false).
true

19> "abc".
[97,98,99]

20> <<226, "Hello">>.
<<226,72,101,108,108,111>>

当你把一个包含整数的二进制文件转换成一个列表(二进制文件只能包含0到255之间的整数),你会得到一个包含相同整数的列表,并且任何整数列表,其中的整数在0到1114111之间,都是string:length()的有效参数。
最后,请注意string:length()不仅仅返回二进制的字节数:

23> string:length(<<195,162,97,98,99>>).
4

string:length()识别出前两个字节,即195、162,是small letter a with circumflex的UTF-8代码,因此它只将两个整数/字节作为一个字符计数。另一方面,如果您先转换为列表,string:length()将返回列表中的整数数:

24> string:length(binary_to_list(<<195,162,97,98,99>>)).
5

......这与byte_size(Binary)得到的答案相同。

vsmadaxz

vsmadaxz2#

评论回复:
我可以得到ASCII、拉丁文或Unicode字符--找到字符串长度的最佳方法是什么?

-module(a).
-compile(export_all).

get_response() ->
    [226,97,98,99,195,162].  %% Remember a double quoted string is just
                             %% a shortcut for creating a list of integers.
%%    ^            ^   ^
%%    |            |   |
%%  latin-1        utf-8
%% small letter a with circumflex

count(Bin) ->
    count(Bin, 0).

count(<<_Head/utf8, Tail/binary>>, Count) ->
    count(Tail, Count+1);
count(<<_Head/integer, Tail/binary>>, Count) ->
    count(Tail, Count+1);
count(<<>>, Count) ->
    Count.

在 shell 中:

32> string:length(list_to_binary(a:get_response())).
** exception error: bad argument: <<226,97,98,99,195,162>>
     in function  string:length_1/2 (string.erl, line 557)

33> string:length(list_to_binary([97,98,99,195,162])).
4

34> Bin = list_to_binary(a:get_response()).
<<226,97,98,99,195,162>>

35> a:count(Bin).
5

注意,get_response()返回一个列表,其中包含small letter a with circumflex的拉丁1整数代码、a的ASCII整数代码以及表示small letter a with circumflex的两个UTF-8整数。二进制允许您指定utf8类型,它将匹配表示UTF-8中的一个字符的一组整数。utf8类型还将匹配0-127范围内的单个整数,count()函数的第二个子句指定了integer类型,它将匹配任何其他整数,例如代码大于127的拉丁-1字符。
二进制还允许指定类型utf16utf32,以匹配表示这些编码中的字符的整数块。

相关问题