您的位置:首页 > 其它

Nim语言中的解析表达文法 pegs模块

2016-01-24 11:24 316 查看

Pegs 模块

简单的PEG(解析表达文法)匹配。没有使用任何记忆,而是用superoperators和符号内联来提升性能。注意:PEG匹配性能是希望与正则表达式引擎竞争的。

更多的有关Nim语言的知识在:https://github.com/ScxMes/Core-Nim-programming/blob/master/%E7%9B%AE%E5%BD%95.md

PEG的语法和语义

一个PEG(解析表达文法)是一个简单的确定性的语法,它可以直接用于解析。当前的实现已经被设计为一个更强大的来替代正则表达式。UTF-8是支持的。

用于PEG的符号与EBNF(扩展巴科斯范式)是相似的。

notationmeaning
A / … / Z顺序选择:应用于表达式A,…,Z,按照这种顺序,从文本的前面开始,直到其中一个成功,并且可能消耗一些文本。如果表达式中只要一个得到满足,则表明成功,否则不消耗任何文本,表明失败。
A … Z序列:应用于表达式A,…Z,按照这个顺序,消耗文本前面连续的部分,只要它们满足。如果都能匹配表明成功,否则不消耗任何文本表明失败。这个序列的优先级要高于顺序选择的优先级:A B / C意思是(A B) / C,而不是A (B / Z)。
(E)分组:圆括号用来改变运算符优先级。
{E}捕获:应用于表达式E,并且存储匹配E的子串,在匹配过程后可以被调用。
$i后向引用第i个捕获,i从1开始。
$锚:匹配输入(字符串)的结尾,不消耗字符,与 !. 一样。
^锚:匹配输入(字符串)的开始,没有字符被消耗。
&E与断言:如果表达式E匹配前面的文本,则表明成功。否则表明失败。不消耗任何文本。
!E非断言:如果表达式E匹配前面的文本,则表明失败。否则表明成功。不消耗任何文本。
E+一个或多个:应用于表达式E多次匹配前面的文本,只要能匹配成功。消耗匹配的文本(如果有的话),并且如果至少满足一个则表明成功,否则失败。
E*零个或多个:应用于表达式E多次匹配前面的文本,只要能匹配成功。消耗匹配的文本(如果有的话)。总是表明成功。
E?零个或一个:如果表达式E匹配前面的文本,消耗它,总是表明成功。
[s]字符分类:如果前面的字符出现在字符串s中,消耗它,并且表明成功,否则失败。
[a-b]字符范围:如果前面的字符是a-b范围中的,消耗它,并且表明成功,否则失败。
’s’字符串:如果前面的文本是字符串s,消耗它,并且表明成功,否则失败。
i’s’忽略大小写的字符串匹配
y’s’忽略拼写风格的字符串匹配
v’s’逐字字符串匹配:使用这个来重载一个全局的 \i 或 \y 修饰符
i$j字符串匹配忽略大小写后向引用
y$j字符串匹配忽略拼写风格后向引用(忽略大小写和下划线等)
v$j逐字字符串匹配后向引用
.任意字符:如果有一个字符在前面,消耗它,并且表明成功,否则(也就是说,在输入的末尾)表明失败。
_任何Unicode字符:如果有一个UTF-8字符在前面,消耗它,并且表明成功,否则表明失败。(下划线)
@E搜索:(!E .)* E 的简写。(循环搜索模式E)
{@} E捕获搜索:{(!E .)*} E。(循环搜索模式E)捕获所有直到不能匹配。
@@ E与 {@} E 相同
A

内置的宏

macromeaning
\d任何十进制数子:[0-9]
\D任何不是十进制数子的字符:[^0-9]
\s任何空格字符: [ \9-\13]
\S任何不是空格的字符: [^ \9-\13]
\w任何”word”字符: [a-zA-Z0-9_]
\W任何”non-word” 字符: [^a-zA-Z0-9_]
\a和 [a-zA-Z]相同
\A和 [^a-zA-Z]相同
\n任何换行符组合: \10 / \13\10 / \13
\i忽略大小匹配;从PEG开始使用
\y忽略拼写风格的匹配; 从PEG开始使用
\skip
pat在试图匹配其他符号之前跳过模式pat ;这个对于跳过空格是有用的,例如: \skip(\s*) {\ident} ‘:’ {\ident} 匹配键值对,忽略 :旁边的空格。
\ident一个标准ASCII标识符: [a-zA-Z_][a-zA-Z_0-9]*
\letter任何Unicode字母
\upper任何Unicode大写字母
\lower任何Unicode小写字母
\title任何Unicode头字母
\white任何Unicode空格字符
一个反斜杠后面跟着一个字母是一个内置的宏,否则它用于普通的转码:

notationmeaning
\\一个反斜杠
\*相当于 ‘*’
\t不是一个跳格键,而是一个(未知)内置

支持PEG语法

PEG解析器实现这个语法(被写入PEG语法):

# Example grammar of PEG in PEG syntax.
# Comments start with '#'.
# First symbol is the start symbol.

grammar <- rule* / expr

identifier <- [A-Za-z][A-Za-z0-9_]*
charsetchar <- "\\" . / [^\]]
charset <- "[" "^"? (charsetchar ("-" charsetchar)?)+ "]"
stringlit <- identifier? ("\"" ("\\" . / [^"])* "\"" /
"'" ("\\" . / [^'])* "'")
builtin <- "\\" identifier / [^\13\10]

comment <- '#' @ \n
ig <- (\s / comment)* # things to ignore

rule <- identifier \s* "<-" expr ig
identNoArrow <- identifier !(\s* "<-")
prefixOpr <- ig '&' / ig '!' / ig '@' / ig '{@}' / ig '@@'
literal <- ig identifier? '$' [0-9]+ / '$' / '^' /
ig identNoArrow /
ig charset /
ig stringlit /
ig builtin /
ig '.' /
ig '_' /
(ig "(" expr ig ")")
postfixOpr <- ig '?' / ig '*' / ig '+'
primary <- prefixOpr* (literal postfixOpr*)

# Concatenation has higher priority than choice:
# ``a b / c`` means ``(a b) / c``

seqExpr <- primary+
expr <- seqExpr (ig "/" expr)*


注意:作为一个特殊的语法扩展,如果整个PEG仅仅是一个表达式,那么标识符不是解释为一个非终结符,而是作为一个逐字的字符串:

import pegs

var abc = "abc"
echo abc =~ peg"abc" # is true


所以在上面这个例子中,是没有必要写成peg” ‘abc’ “的。

例子

检查s是否匹配Nim的”while”关键字:

import pegs

var s = "Whi_le"
echo s =~ peg" y'while'"      #y’while’  忽略大小写和下划线等。


交换(key, val) 对值:

import pegs

var peg1 = peg"{\ident} \s* ':' \s* {\ident}"
echo "key: val; key2: val2".replacef(peg1, "$2: $1")


确定C文件中#inclued的文件:

C文件tc.c:

#include"stdio.h"
#include"math.h"
//author: yrs
/*this is a test file*/

int main() {
printf("Hello Nim!");
return 0;
}


Nim文件:

import pegs

for line in lines("tc.c"):
if line =~ peg"""s <- ws '#include' ws '"' {[^"]+} '"' ws
comment <- '/*' @ '*/' / '//' .*
ws <- (comment / \s+)* """:
echo matches[0]


转换一个PEG为它的字符串表达方式,tpeg.nim:

import pegs
var s = peg"{\ident} \s* '=' \s* {.*}"
echo($s)


测试过程transformFile, ttransformFile.nim:

import pegs

transformFile("infile.txt", "outfile.txt",
[(peg"""S <- {typedesc} \s* {\ident} \s* ','
typedesc <- \ident '*'* """, r"$2: $1")])


过滤文件myfile.txt中的key=value对, tkeyvalue.nim:

# Filter key=value pairs from "myfile.txt"
import pegs

for x in lines("myfile.txt"):
if x =~ peg"{\ident} \s* '=' \s* {.*}":
echo "Key: ", matches[0],
" Value: ", matches[1]


测试过程match和模板
=~
:

import pegs

echo match("(a b c)", peg"'(' @ ')'")
echo match("W_HI_Le", peg"\y 'while'")       #\y 忽略格式匹配

if `=~`("((a b) c)", peg"{'(' @ ')'}"):
echo matches[0]

if `=~`("杨汝生", peg"{_*}"):
echo matches[0]

if `=~`("11aaadd", peg"{.*}"):
echo matches[0]

if `=~`("yrs :a22",peg"\skip(\s*) {\ident} ':' {\ident}"):
echo matches[0]," : ",matches[1]


测试过程replacef:

import pegs

var peg1 = peg"{\ident} \s* ':' \s* {\ident}"
echo "key: val; key2: val2".replacef(peg1, "$2: $1")

echo "var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2")


测试过程
!*
:

import pegs

var
str = "[aadd]aaa]b]qq]ba]q]ss]"#aas[lll]"
peg1 = peg" \] "

for substr in findAll(str, sequence(peg"\[", `!*`(peg1))):
echo substr

peg1 = peg" \[ @ \] "    # @ 应该相当于运算符 `!*`
echo findAll(str, peg1)


import pegs

var
str = "abc123def"
peg1 = peg"(\a)"
peg4: Peg

peg4 = `!*`(peg1)

for sub in findAll(str, peg4):
echo sub
echo "*************"

for sub in findAll(str, peg"@ \a"):           # 运算符`!*` 应该相当于 @
echo sub


测试过程
/
,顺序选择 A / … / Z

import pegs

var
str = "a 1@b"
peg1 = peg"(\d)"
peg2 = peg"(\s)"
peg3 = peg"(\a)"
peg4: Peg
peg5 = peg"(\d)/(\a)"

peg4 = `/`(peg1,peg2,peg3)

for sub in findAll(str, peg4):
echo sub
echo "*************"

for sub in findAll(str, peg1 / peg3):
echo sub
echo "*************"

for sub in findAll(str, peg5):
echo sub


测试过程sequence,序列: A … Z

import pegs

var
str = "a 1@b"
peg1 = peg"(\a)"
peg2 = peg"(\s)*"
peg3 = peg"(\d)"
peg4: Peg
peg5 = peg"(\a) (\s)* (\d)"

peg4 = sequence(peg1,peg2,peg3)

for sub in findAll(str, peg4):
echo sub
echo "*************"

for sub in findAll(str, peg5):
echo sub


测试过程
!*\


import pegs

var
str = "1abc123def"
peg1 = peg"(\a)"
peg4: Peg

peg4 = `!*\`(peg1)           # 运算符 `!*\` 相当于 {@}  或 @@

for sub in findAll(str, peg4):
echo sub
echo "*************"

echo findAll(str, peg"{@} \a")
echo findAll(str, peg"{(!\a .)*} \a")
echo findAll(str, peg"@@ \a")
echo findAll(str, peg"{@ \a}")
echo findAll(str, peg4)


测试与断言:

import pegs

var
str = "abc123de2f"
peg1 = peg"\d & 'd' "      #只有 模式 \d 后面跟的是字母’b'时,才会匹配 \d
peg2: Peg

echo findAll(str, peg1)

peg2 = sequence(peg".", `&`(peg"\d\a'e'"))
#peg2 = `&`(peg"\d\a'e'")   #不能单独使用与断言,机器会崩溃,  与断言前面得有一个表达式。只有与断言后面匹配了,前面的表达式才能捕获。
echo findAll(str, peg2)


测试字符串的起始位和结束位:^ $

import pegs

var
str = "sabc123"
peg1 = peg" ^ \a"
peg2 = peg" \d $"

echo findAll(str, peg1)
echo findAll(str, peg2)


PEG vs regular expression

作为一个正则表达式 [.] 匹配最长可能的文本在 ‘[’ 和 ‘]’之间。作为一个PEG它不会匹配任何东西,因为一个PEG是确定的:. 消耗输入的剩余部分,因此 ] 从来不会匹配。PEG要写成:[ ( !] . )* ] (或者 [ @ ]),会匹配’[’ 和 ‘]’之间的文本,但匹配的是最短的文本。

正则表达式:

import re

for x in findAll("xxx[aadd]aaa]qqq])234xdv", re"\[.*\]"):
echo x


PEG:

import pegs

var
str = "[aadd]aaa]a]qq]aa]q]ss]"
peg1 = peg"\[ @ \]"    #最短匹配
#peg1 = peg"\[ (!(\] (!\] .)* $) . )* \]"    #最长匹配

for substr in findAll(str, peg1):
echo substr


注意:正则表达式没有表现的目的之一:在这个例子中 * 不应该是贪婪的,如果想匹配最短内容则使用 [.*?]。

PEG构造

在Nim中有两种方式来构造一个PEG:

解析一个字符串到一个由Peg节点和Peg过程组成的AST里。

直接调用过程构造AST。这种方法不支持构造规则,仅仅支持简单的表达式,并且是不方便的。它唯一的优势是不把整个PEG解析加入到你的可执行文件中。

pegs模块 types

Peg类型: 这个类型表示一个PEG。

Captures类型: 包含捕获的子字符串。

EInvalidPeg类型:如果发现一个无效的PEG,将会引起异常。

常量

MaxSubpatterns = 20

定义了能够捕获子模式的最大数量,更多的子模式将不能被捕获。

过程

proc term(t: string): Peg {.nosideEffect, gcsafe, extern: "npegs$1Str", raises: [],
tags: [].}

从一个终端字符串构造一个PEG   Source

proc termIgnoreCase(t: string): Peg {.nosideEffect, gcsafe, extern: "npegs$1",
raises: [], tags: [].}

从一个终端字符串构造一个PEG,忽略大小写匹配   Source

proc termIgnoreStyle(t: string): Peg {.nosideEffect, gcsafe, extern: "npegs$1",
raises: [], tags: [].}

从一个终端字符串构造一个PEG,忽略拼写风格匹配(大小写,下划线等)   Source

proc term(t: char): Peg {.nosideEffect, gcsafe, extern: "npegs$1Char", raises: [],
tags: [].}

从一个终端字符构造一个PEG   Source

proc charSet(s: set[char]): Peg {.nosideEffect, gcsafe, extern: "npegs$1", raises: [],
tags: [].}

从一个终端字符集合s构造一个PEG   Source

proc `/`(a: varargs[Peg]): Peg {.nosideEffect, gcsafe, extern: "npegsOrderedChoice",
raises: [], tags: [].}

构造一个顺序选择的PEG,只要满足其中一个则表明成功  Source

proc sequence(a: varargs[Peg]): Peg {.nosideEffect, gcsafe, extern: "npegs$1",
raises: [], tags: [].}

由多个PEGs a 来构造一个序列。对应与 A ... Z   Source

proc `?`(a: Peg): Peg {.nosideEffect, gcsafe, extern: "npegsOptional", raises: [],
tags: [].}

构造一个可选的 PEG a,对应于 a?   Source

proc `*`(a: Peg): Peg {.nosideEffect, gcsafe, extern: "npegsGreedyRep", raises: [],
tags: [].}

构造一个贪婪的重复的 PEG a,对应于a*   Source

proc `!*`(a: Peg): Peg {.nosideEffect, gcsafe, extern: "npegsSearch", raises: [], tags: [].}

构造一个"search" PEG a ,应该相当于 @a   Source

proc `!*\`(a: Peg): Peg {.noSideEffect, gcsafe, extern: "npgegsCapturedSearch",
raises: [], tags: [].}

构造一个捕获搜索的PEG a( "captured search" for the PEG a), 应该相当于 {@} a  或 @@ a。   Source

proc `+`(a: Peg): Peg {.nosideEffect, gcsafe, extern: "npegsGreedyPosRep", raises: [],
tags: [].}

构造一个正向贪婪重复的PEG a,相当于 a+   Source

proc `&`(a: Peg): Peg {.nosideEffect, gcsafe, extern: "npegsAndPredicate", raises: [],
tags: [].}

构造一个与断言的 PEG a,相当于&a   Source

proc `!`(a: Peg): Peg {.nosideEffect, gcsafe, extern: "npegsNotPredicate", raises: [],
tags: [].}

构造一个非断言的 PEG a,相当于 !a   Source

proc any(): Peg {.inline, raises: [], tags: [].}

构造匹配任何字符的PEG: (.)   Source

proc anyRune(): Peg {.inline, raises: [], tags: [].}

构造匹配任何Unicode字符: (_)   Source

proc newLine(): Peg {.inline, raises: [], tags: [].}

构造换行符 PEG:(\n)   Source

proc unicodeLetter(): Peg {.inline, raises: [], tags: [].}

构造匹配任何Unicode字母的 PEG: \letter  Source

proc unicodeLower(): Peg {.inline, raises: [], tags: [].}

构造匹配任何Unicode小写字母的 PEG:\lower   Source

proc unicodeUpper(): Peg {.inline, raises: [], tags: [].}

构造匹配任何Unicode大写字母的 PEG: \upper   Source

proc unicodeTitle(): Peg {.inline, raises: [], tags: [].}

构造匹配任何Unicode title letter(???)的 PEG:\title   Source

proc unicodeWhitespace(): Peg {.inline, raises: [], tags: [].}

构造匹配任何Unicode空格符的 PEG: \white    Source

proc startAnchor(): Peg {.inline, raises: [], tags: [].}

构造匹配输入开始位的PEG ^    Source

proc endAnchor(): Peg {.inline, raises: [], tags: [].}

构造匹配输入结尾的PEG:$    Source

proc capture(a: Peg): Peg {.nosideEffect, gcsafe, extern: "npegsCapture", raises: [],
tags: [].}

构造一个PEG a的捕获,相当与{a}   Source

proc backref(index: range[1 .. MaxSubpatterns]): Peg {.nosideEffect, gcsafe,
extern: "npegs$1", raises: [], tags: [].}

构造一个后向引用的PEG,索引是index,其值从1开始,最大值是MaxSubpatterns(常量20),相当与 $i   Source

proc backrefIgnoreCase(index: range[1 .. MaxSubpatterns]): Peg {.nosideEffect,
gcsafe, extern: "npegs$1", raises: [], tags: [].}

构造一个后向引用的PEG,索引是index,其值从1开始,最大值是MaxSubpatterns(常量20),匹配忽略大小写,相当与 i$j   Source

proc backrefIgnoreStyle(index: range[1 .. MaxSubpatterns]): Peg {.nosideEffect,
gcsafe, extern: "npegs$1", raises: [], tags: [].}

构造一个后向引用的PEG,索引是index,其值从1开始,最大值是MaxSubpatterns(常量20),匹配忽略拼写风格(大小写,下划线等),相当与 y$j   Source

proc nonterminal(n: NonTerminal): Peg {.nosideEffect, gcsafe, extern: "npegs$1",
raises: [], tags: [].}

构造一个由非终结符组成的PEG   Source

proc newNonTerminal(name: string; line, column: int): NonTerminal {.nosideEffect,
gcsafe, extern: "npegs$1", raises: [], tags: [].}

构造一个非终结符号   Source

proc `$`(r: Peg): string {.nosideEffect, gcsafe, extern: "npegsToString", raises: [],
tags: [].}

转化一个PEG为它的字符串表示形式   Source

proc bounds(c: Captures; i: range[0 .. 20 - 1]): tuple[first, last: int] {.raises: [],
tags: [].}

返回第i个捕获的边界 [first..last]    Source

proc rawMatch(s: string; p: Peg; start: int; c: var Captures): int {.nosideEffect,
gcsafe, extern: "npegs$1", raises: [], tags: [].}

底层匹配过程,实现PEG解释器。使用这个来达到最高效率(每一个其他的PEG操作都以调用这个过程结束),如果没有匹配将返回-1,否则返回匹配的长度。   Source

proc matchLen(s: string; pattern: Peg; matches: var openArray[string]; start = 0): int {.
nosideEffect, gcsafe, extern: "npegs$1Capture", raises: [], tags: [].}

和match一样,不过它返回匹配的长度,如果没有匹配,将返回-1。注意一个匹配的长度可能是0. s 的下标可能不属于这个匹配(???)   Source

proc matchLen(s: string; pattern: Peg; start = 0): int {.nosideEffect, gcsafe,
extern: "npegs$1", raises: [], tags: [].}

和match一样,不过它返回匹配的长度,如果没有匹配,将返回-1。注意一个匹配的长度可能是0. s 的下标可能不属于这个匹配(???)   Source

proc match(s: string; pattern: Peg; matches: var openArray[string]; start = 0): bool {.
nosideEffect, gcsafe, extern: "npegs$1Capture", raises: [], tags: [].}

如果s[start..]匹配 pattern,并且捕获子字符串到数组matches里,那么将返回true。如果没有匹配,不会向数组中写数据,并且返回false   Source

proc match(s: string; pattern: Peg; start = 0): bool {.nosideEffect, gcsafe,
extern: "npegs$1", raises: [], tags: [].}

如果s从start出开始匹配pattern,则返回true   Source

proc find(s: string; pattern: Peg; matches: var openArray[string]; start = 0): int {.
nosideEffect, gcsafe, extern: "npegs$1Capture", raises: [], tags: [].}

返回s匹配pattern的开始位置,并且捕获子字符串到数组matches中。如果没有匹配,不写入matches任何数据,并且返回-1   Source

proc findBounds(s: string; pattern: Peg; matches: var openArray[string]; start = 0): tuple[
first, last: int] {.nosideEffect, gcsafe, extern: "npegs$1Capture", raises: [],
tags: [].}

返回字符串s匹配pattern的开始和结束位置,并且捕获子字符串到数组matches中,如果没有匹配,数组不写入任何数据,并且返回(-1,0)  Source

proc find(s: string; pattern: Peg; start = 0): int {.nosideEffect, gcsafe,
extern: "npegs$1", raises: [], tags: [].}

返回s匹配pattern的开始位置,如果没有匹配,将返回-1   Source

proc findAll(s: string; pattern: Peg; start = 0): seq[string] {.nosideEffect, gcsafe,
extern: "npegs$1", raises: [], tags: [].}

返回s匹配pattern的所有子字符串,如果没有匹配,将返回@[]   Source

proc contains(s: string; pattern: Peg; start = 0): bool {.nosideEffect, gcsafe,
extern: "npegs$1", raises: [], tags: [].}

相当于 find(s, pattern, start) >= 0   Source

proc contains(s: string; pattern: Peg; matches: var openArray[string]; start = 0): bool {.
nosideEffect, gcsafe, extern: "npegs$1Capture", raises: [], tags: [].}

相当于 find(s, pattern, matches, start) >= 0   Source

proc startsWith(s: string; prefix: Peg; start = 0): bool {.nosideEffect, gcsafe,
extern: "npegs$1", raises: [], tags: [].}

如果s以pattern为前缀开始,那么返回true   Source

proc endsWith(s: string; suffix: Peg; start = 0): bool {.nosideEffect, gcsafe,
extern: "npegs$1", raises: [], tags: [].}

如果s以pattern为后缀结束,那么返回true   Source

proc replacef(s: string; sub: Peg; by: string): string {.nosideEffect, gcsafe,
extern: "npegs$1", raises: [ValueError], tags: [].}

用字符串by来替代s中的sub部分。匹配捕获的可以通过符号$i和$#访问(看strutils.`%`),例如:

"var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2")

Results in:

"var1<-keykey; val2<-key2key2"

Source

proc replace(s: string; sub: Peg; by = ""): string {.nosideEffect, gcsafe,
extern: "npegs$1", raises: [], tags: [].}

用字符串by来替代s中的sub部分,捕获的数据不能访问   Source

proc parallelReplace(s: string; subs: varargs[tuple[pattern: Peg, repl: string]]): string {.
nosideEffect, gcsafe, extern: "npegs$1", raises: [ValueError], tags: [].}

返回s被subs并行代替改变后的复制   Source

proc transformFile(infile, outfile: string;
subs: varargs[tuple[pattern: Peg, repl: string]]) {.gcsafe,
extern: "npegs$1", raises: [Exception, IOError, ValueError],
tags: [ReadIOEffect, WriteIOEffect].}

读infile文件,执行一个并行性替换(调用parallelReplace),并且写入outfile文件。如果发生一个错误将会引起EIO异常,这个应该用于快速脚本   Source

proc split(s: string; sep: Peg): seq[string] {.nosideEffect, gcsafe, extern: "npegs$1",
raises: [], tags: [].}

切割字符串为子字符串   Source

proc parsePeg(pattern: string; filename = "pattern"; line = 1; col = 0): Peg {.
raises: [ValueError, EInvalidPeg, Exception], tags: [RootEffect].}

以pattern构造一个Peg对象,filename、line、col被用于错误信息,但是它们仅仅提供开始偏移量。parsePeg保持值对pattern内部的line和column数的追踪   Source

proc peg(pattern: string): Peg {.raises: [ValueError, EInvalidPeg, Exception],
tags: [RootEffect].}

以pattern构造一个Peg对象,简写已经被推荐使用原始字符串修饰符,例如:
peg"{\ident} \s* '=' \s* {.*}"
Source

proc escapePeg(s: string): string {.raises: [], tags: [].}

转义s,以至于它被逐字匹配当被用于一个peg时   Source


Iterators

iterator findAll(s: string; pattern: Peg; start = 0): string {.raises: [], tags: [].}

产生所有的s中匹配pattern的子字符串   Source

iterator split(s: string; sep: Peg): string {.raises: [], tags: [].}

切割字符串s为子字符串,
子串被 PEG sep分割. Examples:

for word in split("00232this02939is39an22example111", peg"\d+"):
writeLine(stdout, word)

Results in:

"this"
"is"
"an"
"example"

Source


Templates

template letters(): expr

扩大到 charset({'A'..'Z', 'a'..'z'})   Source

template digits(): expr

扩大到 charset({'0'..'9'})   Source

template whitespace(): expr

扩大到 charset({' ', '\9'..'\13'})   Source

template identChars(): expr

扩大到 charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})   Source

template identStartChars(): expr

扩大到 charset({'A'..'Z', 'a'..'z', '_'})   Source

template ident(): expr

same as [a-zA-Z_][a-zA-z_0-9]*; standard identifier   Source

template natural(): expr

same as \d+   Source

template `=~`(s: string; pattern: Peg): bool

这个调用过程match,并且隐式的声明一个matches数组,这个数组能够在 =~ 作用域内调用:

if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}":
# matches a key=value pair:
echo("Key: ", matches[0])
echo("Value: ", matches[1])
elif line =~ peg"\s*{'#'.*}":
# matches a comment
# note that the implicit ``matches`` array is different from the
# ``matches`` array of the first branch
echo("comment: ", matches[0])
else:
echo("syntax error")
Source
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: