V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xiangyuecn
V2EX  ›  程序员

正则 \s 不同语言的差异 \u0020 \u00A0 快来入坑吧😂

  •  
  •   xiangyuecn ·
    xiangyuecn · 2020-04-08 02:54:46 +08:00 · 2244 次点击
    这是一个创建于 1694 天前的主题,其中的信息可能已经有所发展或是发生改变。

    mark 一下,稍不留神就要坑死人😂 而且是半天摸不清楚原因😂

    ❌java:

    System.out.println(Pattern.compile("^\\s+$").matcher("\u0020\u00A0").find());
    

    👌python3:

    import re;print(re.search('^\s+$', u'\u0020\u00A0'))
    

    ❌python2:

    import re;print(re.search('^\s+$', u'\u0020\u00A0'))
    

    👌C#:

    System.Console.WriteLine(new Regex("^\\s+$").IsMatch("\u0020\u00A0"))
    

    👌js:

    /^\s+$/.test("\u0020\u00A0")
    

    难搞啊。。。ASCII space 。。。Unicode separator

    5 条回复    2020-04-08 11:03:36 +08:00
    sakila
        1
    sakila  
       2020-04-08 08:31:22 +08:00
    关于这个问题你可以看一下字符的类别, `unicodedata.category(unichr)`可以返回 str 的常规类别([general category]( https://en.wikipedia.org/wiki/Unicode_character_property)). 比如中文或一些外文的的声调符号的 category 是`Mn`.

    `unicodedata.normalize(form, unistr)`可以返回 Unicode 字符串 unistr 的普通形式“form”, 有`NFC`, `NFKC`, `NFD`和`NFKD`等, 详细解释见[unicode equivalence]( https://en.wikipedia.org/wiki/Unicode_equivalence)

    比如一段代码:

    ```python
    >>> s = 'Ślusàrski'
    >>> print(s)
    'Ślusàrski'
    ```

    现在是 NFC composition 形式, 也就是'Ś' = 'Ś'

    转换成 NFD decomposition 形式:

    ```python
    >>> print(ascii(unicodedata.normalize('NFD','Ślusàrski')))
    'S\u0301lusa\u0300rski'
    ```

    'Ś' = 'S\u0301'

    因此可以写一个 unicode_to_ascii 的函数:

    >>> s = 'Ślusàrski'
    >>> def unicode_to_ascii(s):
    >>> return ''.join(c for c in unicodedata.normalize('NFD', s)
    >>> if unicodedata.category(c) != 'Mn')
    >>> print(unicode_to_ascii(s))
    Slusarski
    ```

    不知道是否满足题主的问题
    sakila
        2
    sakila  
       2020-04-08 08:31:55 +08:00
    回复不能用 markdown?? 题主将就看吧
    fzhyzamt
        3
    fzhyzamt  
       2020-04-08 09:57:56 +08:00
    Java
    System.out.println(Pattern.compile("\\p{javaSpaceChar}").matcher("\u0020\u00A0").find());

    Python2
    print(re.search('^\s+$', u'\u0020\u00A0', flags=re.UNICODE))
    onecode
        4
    onecode  
       2020-04-08 10:21:02 +08:00
    对于我这种正则菜鸟来说,用了正则一个 bug 变两个 bug
    xiangyuecn
        5
    xiangyuecn  
    OP
       2020-04-08 11:03:36 +08:00
    @sakila @fzhyzamt 哈哈,你们的处理方法都没毛病。

    我这个帖子其实是想表达\s 在不同语言下直接使用可能会有问题,需要留意;比如 js 里面用的好好的,直接 copy 到 java 里面可能就不能用了,需要针对各自语言学习各自的特殊处理方案,使用成本急剧增加。

    本来我以为那种非常简单的正则表达式在哪都通用的,没想到不是😁 出现'\u00A0'目前接触到的比较多的还是网页内 html 编辑器 js 插入的连续空白,人工输入基本上不太可能会输入'\u00A0',但 js 最终获取编辑的内容时,如果没有把空格替换回来就会在最终贴子里面出现'\u00A0'字符(比如:微信支付的文档)。好像不同浏览器对'\u00A0'的解析显示也是有差异的,蛋疼
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3590 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 00:09 · PVG 08:09 · LAX 16:09 · JFK 19:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.