各编程语言正则库的小差异

我的笔记,写得乱。。不过本身看得懂就好了—_—html

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

可虽说各编程语言基本都属于 PCRE 派,实现上却仍是各有特色,一个正则想在各语言间移植,也每每须要一番修改。python

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

1、正则库方法上的差异

1.1 模式匹配

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

1.2 分组命名

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

1.3 字符串替换

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

2、正则书写上的差异

  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小写z 表示字符串的绝对的结尾。(不论结尾是否是换行),可 Python 恰恰用 \Z 来表示绝对结尾,而且 Python 里不存在\z这个定位符。

express

待续编程

其余须要注意的

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

参考

相关文章
相关标签/搜索