概要
nimのPEG操作関連処理をコツコツと書いていく予定
nimでは、正規表現ライブラリ(re)もありますが、PEG(pegs)も標準で入っています。
正規表現ライブラリはimpure(OS環境依存ってこと?)、PEGはpureライブラリ(nimで実装)となっているので、PEGを使ったほうがいいのかなーという印象です。
以下メモ
シンプルなマッチング
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
スイッチ
import strutils,pegs,unicode
block:
# 大文字・小文字を無視
echo "abc" =~ peg"i'ABC'"
# スタイルを無視(使う場面あるかな?)
echo "Abc_Def" =~ peg"y'AbcDef'"
(stdout)
true
true
ちょっと複雑なマッチング
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)
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
肯定先読み
import strutils,pegs,unicode
block:
echo "マッチ⇒","ABCDEFGHI" =~ peg"{ABC&DEF}"
echo "マッチした文字⇒", matches[0]
echo "アンマッチ⇒","ABCDGHIEF" =~ peg"ABC&DEF"
(stdout)
マッチ⇒true
マッチした文字⇒ABC
アンマッチ⇒false
否定先読み
import strutils,pegs,unicode
block:
echo "マッチ⇒","ABCDGHIEF" =~ peg"{ABC!DEF}"
echo "マッチした文字⇒", matches[0]
echo "アンマッチ⇒","ABCDEFGHI" =~ peg"ABC!DEF"
(stdout)
マッチ⇒true
マッチした文字⇒ABC
アンマッチ⇒false
マッチしたか(match)
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)
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)
パターンに一致する部分をすべて取り出す
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
パターンに一致するものが含まれるか?
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
部分一致
import strutils,pegs,unicode
block:
echo "abcdef".startsWith(peg"abc")
echo "abcdef".endsWith(peg"def")
(stdout)
true
true
文字列置換
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
分割
import strutils,pegs,unicode
block:
# c / f / i で分割する
for x in "abcdefghijkl".split(peg"c/f/i") :
echo x
(stdout)
ab
de
gh
jkl
関数定義サンプル
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
パラメータの解析
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