各編程語言正則庫的小差異

我的筆記,寫得亂。。不過本身看得懂就好了—_—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 選項時,此選項會被忽略)
  • 懶惰匹配:
    正則匹配默認都是貪婪模式,懶惰匹配要在重複限定符後多加一個?,表示匹配儘量少的字符。好比.*要改爲.*?

參考

相關文章
相關標籤/搜索