• Java/Python/Elixir 正则库使用上的注意事项


    个人笔记,写得乱。。不过自己看得懂就行了—_—

    日常工作中能接触到的正则,分为两大派别,其中 Unix-Like 系统中常用的正则,属于 POSIX “派”(较弱),而各编程语言标准库中的 Re,基本都是 PCRE “派”。(详见 正则表达式“派别”简述

    可虽然说各编程语言基本都属于 PCRE 派,实现上却还是各有特点,一个正则想在各语言间移植,也往往需要一番修改。

    今天学 Elixir,就在正则上遇到了问题,百度一番,想想索性就把这些差别总结一遍,防止下次又掉坑里。(包括 Python、Java、Elixir、文本编辑器的正则,有时间把 SQL 的正则也写写。。)

    一、正则库方法上的差别

    1.1 模式匹配

    1. 文本编辑器的正则是用来搜索的,会匹配整段文本中所有符合该模式的字符串,可以叫做 find all
    2. 而不同的编程语言,又要看方法设计上的理念差别:
      • Python 提供了以下方法
        • match:要求必须从字符串开头开始尝试匹配,相当与使用了 PCRE 的 anchored(锚定)模式。(或者说自动在正则开头添加了A,它在 Python 中表示字符串开头)
        • fullmatch:要求必须匹配整个字符串,相当于在正则的开头添加 A,末尾添加 (它在 Python 中表示字符串末尾).
        • search:从字符串中搜索该模式,找到第一个就返回。
        • findall/finditer:这个就对应 editor 的搜索模式,会返回字符串中所有匹配该模式的子字符串
      • Java:Matcher.matches(),尝试将pattern应用到整个字符串上,相当于 py 的 fullmatch().
      • Elixir,它的 re 只是对 erlang 的一个简单封装。
        • match? :返回 boolean 值,表示是否匹配成功。和 py/java 不同,这个 match? 感觉更像 py 的 search,不过返回值要换成 boolean.所以如果要匹配整个字符串,Axxxz还挺常用的。
        • named_captures,类似 py 的 search + groupdict()

    1.2 分组命名

    1. 这方面就 Python 的语法和其他的不同,它使用 (?P<name>your regex)来为分组命名,而标准语法需要去掉字符P. 在正则中 Python 的分组引用方法有(?P=name) g<name> 1 2,前俩好像都是 Python 独有的。只有 1 2 通用。

    1.3 字符串替换

    1. 文本编辑器(Sublime/Jetbrains/VSCode)在替换字符串中,使用 $1 $2... 来表示前面捕获的数字分组(在正则中仍然可用 1 2,但是替换字符串中必须用 $1 $2
    2. Python 中,替换函数为re.sub re.subn(是的,不是叫 replace,而是 substitution 的缩写)。而且使用 1 2(是的,和正则中的 backreference 一样)来引用前面捕获的分组。(如果命名了分组,也可使用g<name>,但是带P的那个语法就不支持了)

    二、正则书写上的差别

    1. Python 有 raw 字符串,Elixir 也有对应的 sigils,在这种字符串里,正则不需要用一大堆反斜线(slash)来转义,而 Java 就不得不如此。
    2. Elixir 的 sigils 引用符有 8 种,Python 的字符串引用符也有两种(单引号和双引号),可以通过灵活地换用它们来进一步避免使用转义符。
    3. 匹配 flags 的指定方式:
      • 通用写法:可以在正则开头添加(?aiLmsux)来指示开启哪些 flags
      • Elixir:写在引用符的最后,eg. ~r/your regex/ss 表示 dot matches all。
    4. 定位点(开头、结尾):
      这一部分感觉不同工具很不一致,有必要写下来
      • 编辑器:默认是打开了多行模式(multiline)的,也就是说^匹配字符串开头或者任意一行的开头:$匹配字符串的结尾(若结尾有换行,匹配到换行前面的位置),或者任意一行的结尾。
      • 所有的编程语言:默认都不是多行模式,^只匹配字符串开头,$只匹配字符串结尾(若结尾有换行,匹配到换行前面的位置)。

    NOTE:但是这里还有个坑,Elixir、Java、C# 都使用 A 来标识字符串的开头,用  来表示字符串结尾(若结尾有换行,匹配到换行前面的位置,和 $ 一样),z小写z 表示字符串的绝对的结尾。(不论结尾是不是换行),可 Python 偏偏用  来表示绝对结尾,并且 Python 里不存在z这个定位符。

    待续

    其他需要注意的

    1. . 默认是匹配除非换行外的任何字符。如果需要包括换行,需要开启dot matchs all 选项,或者使用大小写匹配符结合(如 [sS] [wW] 之类)
    2. 所有重复限定符(* + ? {m,n}),默认都是贪婪匹配,如果需要懒惰匹配,要在后面多加个?,变成 *? +? {m,n}?
    3. 如果字符串结尾有换行符,$ 会匹配换行符前面的位置。(也就是说这时它匹配到的位置不是真正的结尾)如果一定要匹配到结尾,需要用 (Python 应用大写的Z,而 Elixir C# Java 应用小写z)
      • 或者也可以开启 dollar_endonly 选项,该选项开启后,$就匹配字符串的绝对结尾。(但是在开了 m 选项时,此选项会被忽略)
    • 懒惰匹配:
      正则匹配默认都是贪婪模式,懒惰匹配要在重复限定符后多加一个?,表示匹配尽可能少的字符。比如.*要改成.*?

    参考

  • 相关阅读:
    pythonchallenge10
    线程同步
    查缺补漏
    查看QQ是否在线
    project euler10
    Toon Shading, step 2
    一种简易的卡通渲染方法(上)
    GLSL学习笔记 9.1 Transformation
    Gloss Mapping
    一种简易的卡通渲染方法(下)
  • 原文地址:https://www.cnblogs.com/kirito-c/p/9310908.html
Copyright © 2020-2023  润新知