LoginSignup
10
4

More than 5 years have passed since last update.

nim文字列操作(PEG)

Last updated at Posted at 2016-05-29

概要

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
10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4