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(扩展巴科斯范式)是相似的。
notation | meaning |
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 |
内置的宏
macro | meaning |
\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空格字符 |
notation | meaning |
\\ | 一个反斜杠 |
\* | 相当于 ‘*’ |
\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
相关文章推荐
- csdn MarkDown 使用小记
- 【解题报告】嵌套矩形
- NIO学习笔记(1)之组成、NIO与IO区别、NIO和IO如何影响应用程序的设计和通道
- vb.net知识小汇总
- Valid Sudoku
- Android实现2048小游戏
- nagios安装配置
- ajax--xhr属性方法&post实例
- USACO--Palindromic Squares
- Nim语言中的解析表达文法 pegs模块
- 设计模式:工厂模式
- HDU-5584-LCM Walk【2015上海赛区】【数论】
- JAVA多线程之单例模式
- 欢迎使用CSDN-markdown编辑器
- /var/log目录下的20个Linux日志文件功能详解
- android之桌面悬浮框
- Android HTML5 Video视频标签自动播放与自动全屏问题解决
- css和javascript的一些笔记(四) xml语言基础知识
- python实现的二分查找
- linux命令介绍——Jps