天天看點

nim語言的正規表達式regex入門

nim語言的re子產品是包裝了c語言的庫pcre. 提供了很多的proc供調用.

主要的 函數就是find, findBounds, findAll

1. findBounds查找某個規則的字元串.

例如: 

import re

let
  currentline = "[chapter Uno] and {style} [chapter dos]."
  regex = re"\[chapter(\s+)(.*?)\]"

proc testStrings() =
  var matches: seq[string] = @["", ""]
  let (start, e) = currentline.findbounds(regex, matches)
  echo "testStrings"
  echo "start: ", start, " end: ", e, " matches: ", matches.repr

proc testStringIndices() =
    var matches: seq[string]
    matches.newSeq(2)
    let (start, e) = currentline.findbounds(regex, matches)
    echo "testIndices"
    echo "start: ", start, " end: ", e, " matches: ", matches.repr

proc testIndices() =
  var matches: seq[tuple[first, last: int]]
  matches.newSeq(2)
  let (start, e) = currentline.findbounds(regex, matches)
  echo "testIndices"
  echo "start: ", start, " end: ", e, " matches: ", matches.repr



when isMainModule:
  testStrings()
  testIndices()
  testStringIndices()
           

其中 findBounds 要注意的就是, 這個函數帶了一個matches 的可以重載的參數(這個參數在函數外部定義, 然後在函數内部被覆寫數值)

尤其是要注意的是, findBounds, 隻能一次找到一個符合規則的字元串, 如果想找到全部的字元串, 要自己寫循環來捕捉分組.

捕捉分組要注意的是, matches 最開始一定在定義後, 進行初始化, 如果不進行初始化, matches就不能被重載指派.

例如

import re

var ms:seq[string]
ms.newSeq(2) #這裡一定要初始化, 或者使用var ms: seq[string] = @["", ""] 這種方式進行指派初始化
var rs:tuple[first:int, last:int]
var pattern:Regex = re"""href=\"(/(\w+)/(\w+).html)\""""
rs = findBounds(data,  pattern,  ms, 0)
echo  ms
           

如果不指派, 例如

import re

var ms:seq[string]
#ms.newSeq(2) #這裡一定要初始化, 或者使用var ms: seq[string] = @["", ""] 這種方式進行指派初始化
var rs:tuple[first:int, last:int]
var pattern:Regex = re"""href=\"(/(\w+)/(\w+).html)\""""
rs = findBounds(data,  pattern,  ms, 0)
echo  ms
           

注釋掉之後, echo ms 就是一個空的@[]

另外, seq[string]可以用一個array進行替代, 

var ms:array[2,string] #定義一個數組,類型為string, 長度為2, 這個array可以不進行初始化, 使用後可以得到合适的值.

例如:

import re

var ms:array[2,string] #ms這裡不用初始化

var rs:tuple[first:int, last:int]
var pattern:Regex = re"""href=\"(/(\w+)/(\w+).html)\""""
rs = findBounds(data,  pattern,  ms, 0)
echo  ms
           

2. findBounds 找到全部符合條件的字元串

直接用while寫個循環.

findBounds傳回一個tuple,假設名為 rs, rs.first 是符合regex的第一個字元的位置, rs.last是最後一個字元的位置

echo data[rs.first..rs.last]

可以獲得第一次查找到的字元串, 這個時候, 函數已經結束,并且不再查找後面符合條件的字元串.

要找到後面符合條件的字元串, 要自己寫個while函數, 不斷循環到資料的結尾.

例如

var ms: array[3, string] #捕獲3個組(group)
var rs:tuple[first:int, last:int]
var pattern:Regex = re"""href=\"(/(\w+)/(\w+).html)\"""" #這裡定義了3個組,順序為(全部), (子串1), (子串2)

var start = 0
rs = findBounds(data,  pattern,  ms, 0)
echo data[rs.first..rs.last]
while rs.first>0:
    echo data[rs.first..rs.last]
    echo ms
    start = rs.last+1
    rs = findBounds(data,  pattern,  ms, start)
           

這裡要注意的就是, nim語言的re子產品沒有python的好用, python的group捕獲是自動的, 動态語言給了我們太多的友善, 這裡再nim語言就沒有這個友善了.

3. findAll

findAll 隻能輸出(全部)比對, 在(fasdf(子串1)fasdkfjl(子串2)ddsa) 這種隻能輸出最長的字元串(全部), 是以這裡就不要幻想有python的那麼友善了, 用完findAll, 在循環輸出的時候, 還要配合使用findBounds, 再進行比對子串.

var matches:array[i, string] #i是你要比對的子串組的個數
for line in findAll(data, regex):
    findBounds(line, regex2, matches,start=0)
    echo matches
           

以上為僞代碼. 請自己測試.

參考資料: https://forum.nim-lang.org/t/593

繼續閱讀