【sync】字符串编码

前言

发现这块的坑没人重视过,在此进行总结

该文章同步于 https://github.com/JuliaRoadmap/zh/blob/master/docs/advanced/string_code.md ,以后advanced/中的新内容可能也会在社区同步,便于讨论修改

如果有空可以插入svg便于理解

字符串编码

Julia 中的String并不具有一个特定的编码类型,包括但不限于ASCIILatin-1UTF-8UCS-2UTF-16UTF-32,每个字符占据一定的连续空间,但仍以Char形式导出

Julia 中String所采用的编码的基本假设是自同步(self-synchronizing)

以该字符串s为例(UTF-8):

直观编号 Char 所占字节数
1 3 1
2 θ 2
3 3

相关函数

函数原型 描述 举例 备注
length(s::AbstractString)->Int s的直观字符数 length(s) = 3 时间复杂度与字符串长度线性相关
ncodeunits(s::AbstractString)->Int s的实际字节数 length(s) = 6 也可用sizeof
ncodeunits(c::Char)->Int UTF-8格式表示c所需字符数 ncodeunits('猫') = 3
length(s::AbstractString,i::Integer,j::Integer)->Int s中实际字节i~j所包含的直观字节数(识别开头位置),特别地,当i为ncodeunits(s)+1或j为0时返回0 length(s,3,4) = 1
isvalid(s::AbstractString,i::Integer)->Bool s的第i各字节是否是某个字符空间块的起点 isvalid(s,5) = false
getindex(s::AbstractString,i::Int)->Char 获取s的第i个字节所在字符,i为该字符空间块的起点 s[4] = '猫'
getindex(s::AbstractString,r::UnitRange{Integer})->String 通过实际字节索引获取s的子字符串,其中isvalid(s,r.start)isvalid(r.stop) s[2:4] = "θ猫"
thisind(s::AbstractString,i::Integer)->Int 获取第i个字节所在字符空间块的起点,特别地,当i为0或ncodeunits(s)+1时返回i thisind(s,5)=4 错误抛出BoundsError
nextind(str::AbstractString,i::Integer,n::Integer=1)->Int n=1时返回s中跟随在下标i后面的合法字符字节下标,详见对应帮助 nextind(s,0,3) = 4 可以通过nextind(s,0,i)获取第i个直观字符的空间块起点
prevind(str::AbstractString,i::Integer,n::Integer=1)->Int n=1时返回s中跟随在下标i前面的合法字符字节下标,详见对应帮助 /
codeunit(s::AbstractString)->Type{<:Union{UInt8, UInt16, UInt32}} 导出s编码的bit数 codeunit(s) = UInt8
codeunit(s::AbstractString,i::Integer)->Union{UInt8, UInt16, UInt32} 导出s在实际编号i处的数据 codeunit(s,1) = 0x33 codeunit(s, i)::codeunit(s)
codeunits(s::AbstractString) 导出s的全部字节数据 Vector{UInt8}(codeunits(s))[1] = 0x33

!!! note

通常来说,如果使用直观索引,越界抛出`BoundsError`

如果使用实际字节索引,使用`isvalid`进行边界检查,越界抛出`StringIndexError`

Unicode中也提供了一些相关函数 (链接不可用)

julia> gr=Base.Unicode.graphemes("x𝗑𝘅𝘹𝙭𝚡x𝐱×х⨯ⅹ")
length-12 GraphemeIterator{String} for "x𝗑𝘅𝘹𝙭𝚡x𝐱×х⨯ⅹ"

julia> for c in gr
           println(c)
       end
x
...

相关资源

2 个赞

额外的坑:
length 其实的输出有时并不直观,尤其是涉及复杂 unicode 时。
大家默认的”看上去的长度“也难定义。

标准库的 Unicode.graphemes 可能才符合人”看上去的长度“

2 个赞

这文章看得我,
如果有人用空把这块写成一个清晰的东西的话请放到knowledge/unicode_code.md,unicode包相关内容放入packages/unicode.md,谢谢

一般来说大部分用户不太关心,也不用关心到我说的那一种情况。

字符串这里其实完全可以不提这一点。


我其实想给 Unicode 标准库写一个简要的用法。
稍微写几句就发现,如果不深入,你就无法说明 Unicode.graphemes 实际的用途,和它与 length 的区别。
深入一点,有一些 unicode 的名词。也都不太好解释。
我对 unicode 的理解也不深,没办法深入浅出的讲解这些专有名词。

目前我想到的办法就是,用一些专有名词,但不解释。只提供外部参考资料。
多使用示例演示各个函数的区别,给出一些简要的指南,什么时候考虑用 Unicode 库里的函数。


还有一点:虽说是标准库,但 julia 的不少标准库,实际上是用于保留不适合放在 base 的函数的。
就如 Unicode.graphemes 一样,都是导出的函数,但一般没人使用,所遗留在标准库里。
但如果你想用 Unicode 多做一些 unicode 的处理,查询一些 unicode 的元信息,他又做不到,缺少实用的 API。
就有点尴尬,略显鸡肋。

1 个赞

(没写完也可以发pull request,可以慢慢补充,包括吐槽那段可以放到ecosystem/stdlib.md

BinaryWrappers里wrap了Perl,不知道有没有用

外部参考资料可以挑重点概况翻译下