一些语言中 String 的坑 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
oldshensheep
V2EX    分享发现

一些语言中 String 的坑

  •  
  •   oldshensheep 2022-05-12 14:17:13 +08:00 2360 次点击
    这是一个创建于 1294 天前的主题,其中的信息可能已经有所发展或是发生改变。

    什么 BUG

    这个问题不是 JaaScript 特有,只是记录一下。
    其实就是 String 的长度的问题。String.length 得到的不是字符数

    let str = '哈哈'; console.log(str.length) //8 

    emoji 占了 2 个长度,这个问题在 js 、java 、go 上有,其他语言还没有测试。
    同样的,一些内置函数也受到了这个问题的影响。

    let str = '哈哈'; console.log(str.substring(0, 2)); //哈哈 console.log(str.substring(0, 3)); //哈哈 //意料之外的结果 console.log(str.substring(0, 4)); //哈哈 

    还有 String.charAt()等等
    对于 js 解决办法就是把字符串转换成数组

    let str = '哈哈'; console.log([...str].length) //5 

    日常开发中可能大家都依赖 String.length ,但是在某些情况下可能会出 BUG ,比如要遍历字符串的时候,当然如果你确保输入的字符串不会有那些特殊字符那就没问题了。

    BUG 现场

    记录一下我遇到的 bug ,还有处理方法。总的来说就是变成数组

    let bug = '哈哈'; console.log(bug.length) //8 console.log([...bug].length) //5 console.log(bug.split("").reverse().join("")) //哈哈 console.log([...bug].reverse().join("")) //哈哈 console.log(bug.substring(0, 3)); //哈哈 console.log([...bug].slice(0, 3).join("")); //哈哈 
    第 1 条附言    2022-05-12 15:03:59 +08:00
    对于 Javascript 大家不要用我说这个方法了吧……
    [...str]还是会出 bug 可以用#3 楼提供的库,其他语言应该也有类似的。
    主要就是提醒大家编程遍历字符串的时候要注意这个问题。
    15 条回复    2022-05-12 15:29:44 +08:00
    zagfai
        1
    zagfai  
       2022-05-12 14:23:12 +08:00
    字符长度与字节长度是两回事
    DiamondYuan
        2
    DiamondYuan  
       2022-05-12 14:32:18 +08:00   1
    你的处理方法还是会有 bug

    console.log([...""].reverse().join(""));
    DiamondYuan
        3
    DiamondYuan  
       2022-05-12 14:33:02 +08:00   2
    oldshensheep
        4
    oldshensheep  
    OP
       2022-05-12 14:40:02 +08:00
    @DiamondYuan 看来还是不行……有点坑人。
    这个字符我按删除键,变成了另外一个字符……
    pocarisweat
        5
    pocarisweat  
       2022-05-12 14:42:59 +08:00   3
    你可以试试更复杂的情况,比如彩虹旗,这个 emoji 实际上是 2 个 emoji (彩虹+白旗)和中间的连接符拼起来的,在 UTF-16 的情况下长度应该是 6 (比如 Javascript )。大概只有 Swift 会把它当作一个字符:

    1> "".count
    $R0: Int = 1
    pocarisweat
        6
    pocarisweat  
       2022-05-12 14:44:34 +08:00
    @oldshensheep
    如果你用的是 Firefox ,那按删除键变成另一个字符是 bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1728746
    oldshensheep
        7
    oldshensheep  
    OP
       2022-05-12 14:50:49 +08:00
    @pocarisweat 确实是用 Firefox 。不过 Chrome 的地址栏也有这个问题,要按 3 下才能删除( Firefox 是 2 下),网页中的输入框没问题( Firefox 有问题)。
    rabbbit
        8
    rabbbit  
       2022-05-12 14:51:31 +08:00
    I have a , I have a . Uh!
    rabbbit
        9
    rabbbit  
       2022-05-12 14:53:07 +08:00
    这个字符是 + ZWJ +
    ipwx
        10
    ipwx  
       2022-05-12 14:54:44 +08:00
    其实让我比较惊讶的是

    console.log(str.length) //8
    console.log([...str].length) // 5

    别的语言要么都是 8 ,要么都是 5 。不愧是大 JS ,继三位一体不等式以后,又出现了新的不一致性。
    hsfzxjy
        11
    hsfzxjy  
       2022-05-12 14:55:53 +08:00
    说到底还是“字符”的定义产生的混淆。你是想要 code point 还是 grapheme

    https://stackoverflow.com/questions/27331819/whats-the-difference-between-a-character-a-code-point-a-glyph-and-a-grapheme
    ipwx
        12
    ipwx  
       2022-05-12 14:56:31 +08:00
    In [1]: S = '哈哈'

    In [2]: S[::-1]
    Out[2]: '哈哈'

    In [3]: len(S)
    Out[3]: 5
    xiangyuecn
        13
    xiangyuecn  
       2022-05-12 14:59:09 +08:00
    这个本身就是玄学,单纯肉眼可见的长度,你还得考虑大量的零宽字符:明明就显示的两个字,文件却有 1 个 G 大小

    另外:emoji 有一个连接字符,\u2***多少来着,几个 emoji 连接显示成一个 emoji ,目测可以无限套娃
    billlee
        14
    billlee  
       2022-05-12 15:22:23 +08:00
    ucs-2 的历史遗留问题,java 也有,python 没有
    xtreme1
        15
    xtreme1  
       2022-05-12 15:29:44 +08:00
    大部分的 string 问题都是允许按下标访问
    如果把 string 和 char array 彻底分开就没这些问题,string 只开放迭代器
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3114 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 21ms UTC 11:32 PVG 19:32 LAX 03:32 JFK 06:32
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86