nim文字列操作(PEG)

# 概要
nimのPEG操作関連処理をコツコツと書いていく予定
nimでは、正規表現ライブラリ(re)もありますが、PEG(pegs)も標準で入っています。
正規表現ライブラリはimpure(OS環境依存ってこと？)、PEGはpureライブラリ(nimで実装)となっているので、PEGを使ったほうがいいのかなーという印象です。
## 以下メモ
### シンプルなマッチング
```nim
import strutils,pegs,unicode
block:
  echo "1"       =~ peg"\d"
  echo "123"     =~ peg"\d+"
  echo "123ABC"  =~ peg"\d+\w+"
  echo "123_ABC" =~ peg"\d+_\w+"
```
```
(stdout)
true
true
true
true
```
### スイッチ
```nim
import strutils,pegs,unicode
block:
  # 大文字・小文字を無視
  echo "abc" =~ peg"i'ABC'"
  # スタイルを無視(使う場面あるかな？)
  echo "Abc_Def" =~ peg"y'AbcDef'"
```
```
(stdout)
true
true
```
### ちょっと複雑なマッチング
```nim
import strutils,pegs,unicode
block:
  # 識別子が空白区切りで複数存在する
  let pegstr = peg("""
grammar <- ws* rule+
rule <- {\ident} ws*
ws <- \s+
  """)
  echo "1)"
  echo "" =~ pegstr
  echo "2)"
  echo "abc" =~ pegstr
  echo matches.len
  echo matches[0]
  echo "3)"
  echo "abc def" =~ pegstr
  echo matches[0]
  echo matches[1]
  echo "4)"
  echo "abc def ghi" =~ pegstr
  echo matches[0]
  echo matches[1]
  echo matches[2]
  echo "5)"
  echo "abc def ghi XYZ" =~ pegstr
  echo matches[0]
  echo matches[1]
  echo matches[2]
  echo matches[3]
  for x in 0..19:
    matches[x] = nil
  echo "6)"
  echo "改行テスト"
  echo "ABC\nDEF\nGHI\nJKL " =~ pegstr
  echo matches[0]
  echo matches[1]
  echo matches[2]
  echo matches[3]
```
```
(stdout)
1)
false
2)
true
20
abc
3)
true
abc
def
4)
true
abc
def
ghi
5)
true
abc
def
ghi
XYZ
6)
改行テスト
true
ABC
DEF
GHI
JKL
```
### 一致した文字数が返却される(rawMatch)
```nim
import strutils,pegs,unicode
block:
  var c : Captures
  echo "abcDEF".rawMatch(peg"abc",0, c)
  echo "abcDEF".rawMatch(peg"DEF",0, c)
  # rawMatchと変わらない？
  echo "abc".matchLen(peg"abc")
  echo "abcabc".matchLen(peg"(abc)+")
```
```
(stdout)
3
-1
3
6
```
### 肯定先読み
```nim
import strutils,pegs,unicode
block:
  echo "マッチ⇒","ABCDEFGHI" =~ peg"{ABC&DEF}"
  echo "マッチした文字⇒", matches[0]
  echo "アンマッチ⇒","ABCDGHIEF" =~ peg"ABC&DEF"
```
```
(stdout)
マッチ⇒true
マッチした文字⇒ABC
アンマッチ⇒false
```
### 否定先読み
```nim
import strutils,pegs,unicode
block:
  echo "マッチ⇒","ABCDGHIEF" =~ peg"{ABC!DEF}"
  echo "マッチした文字⇒", matches[0]
  echo "アンマッチ⇒","ABCDEFGHI" =~ peg"ABC!DEF"
```
```
(stdout)
マッチ⇒true
マッチした文字⇒ABC
アンマッチ⇒false
```
### マッチしたか(match)
```nim
import strutils,pegs,unicode
block:
  echo "abc".match(peg"abc")
  echo "abcDEF".match(peg"{\w+}")
  echo "abcDEF".matchLen(peg"{\w+}")
```
```
(stdout)
true
true
6
```
### 検索する(find,findBounds)
```nim
import strutils,pegs,unicode
block:
  echo "abcXYZ".find(peg"XYZ")
  echo "public sub sample()".find(peg"sub \s+ {\ident} \s* \(")
  # 見つけた位置を返却
  var m : array[0..19, string]
  echo "abcXYZ".findBounds(peg"XYZ",m,0)
```
```
(stdout)
3
7
(first: 3, last: 5)
```
### パターンに一致する部分をすべて取り出す
```nim
import strutils,pegs,unicode
block:
  echo "abc".findAll(peg"abc").join("/")
  echo "abc def abc".findAll(peg"abc").join("/")
  echo "abc \n abc \n abc \n".findAll(peg"abc").join("/")
```
```
(stdout)
abc
abc/abc
abc/abc/abc
```
### パターンに一致するものが含まれるか？
```nim
import strutils,pegs,unicode
block:
  echo "abc".contains(peg"abc")
  var m : array[0..19,string]
  echo "abc def ghi abc".contains(peg"{abc}",m,6)
  echo m[0]
```
```
(stdout)
true
true
abc
```
### 部分一致
```nim
import strutils,pegs,unicode
block:
  echo "abcdef".startsWith(peg"abc")
  echo "abcdef".endsWith(peg"def")
```
```
(stdout)
true
true
```
### 文字列置換
```nim
import strutils,pegs,unicode
block:
  # 置換
  echo "abc def ghi def".replace(peg"def/ghi","DEF")
  # フォーマット付き置換
  echo "abc def ghi def".replacef(peg"{def/ghi}","[$1]")
  # 複数の置換
  var keyval = @[
    ( pattern: peg"abc" , repl: "ABC" ),
    ( pattern: peg"def" , repl: "DEF" )
  ]
  echo "abc def ghi".parallelReplace(keyval)
```
```
(stdout)
abc DEF DEF DEF
abc [def] [ghi] [def]
ABC DEF ghi
```
### 分割
```nim
import strutils,pegs,unicode
block:
  # c / f / i で分割する
  for x in "abcdefghijkl".split(peg"c/f/i") :
    echo x
```
```
(stdout)
ab
de
gh
jkl
```
### 関数定義サンプル
```nim
import strutils,pegs,unicode
block:
  var pegPattern = peg("""
  funcdef     <- {access} \s+ {returntype} \s+ {funcname}
  access      <- 'public' / 'private' / 'protected'
  returntype  <- \ident
  funcname    <- \ident
  """)
  echo "public void sample()" =~ pegPattern
  for x in matches:
    if x != nil : echo x
```
```
(stdout)
true
public
void
sample
```
### パラメータの解析
```nim
import strutils,pegs,unicode
block:
  var pegParameters = peg("""
  parameters    <- lparen ws headParameter restParameter* ws rparen
  parameter     <- {\ident} sp {\ident}
  headParameter <- parameter
  restParameter <- ',' ws parameter
  lparen        <- '('
  rparen        <- ')'
  sp            <- \s+
  ws            <- \s*
  """)
  # パース＆結果表示
  proc showResults(target: string, pattern: Peg): int {.discardable.} =
    echo "[",target,"]"
    discard target =~ pattern
    for i,x in matches :
      if x != nil :
        if i mod 2 == 0 :
          echo "data type = ",x
        else :
          echo "var name  = ",x
  "(int a)".showResults(pegParameters)
  "(int a,int b)".showResults(pegParameters)
  "(int a,string b,float c)".showResults(pegParameters)
```
```
(stdout)
[(int a)]
data type = int
var name  = a
[(int a,int b)]
data type = int
var name  = a
data type = int
var name  = b
[(int a,string b,float c)]
data type = int
var name  = a
data type = string
var name  = b
data type = float
var name  = c
```