1
0
mirror of https://github.com/apachecn/eloquent-js-3e-zh.git synced 2025-05-23 11:52:20 +00:00
This commit is contained in:
wizardforcel 2018-05-07 11:11:18 +08:00
parent 7b13530dec
commit eef0576d16
5 changed files with 614 additions and 46 deletions

106
9.md
View File

@ -1,9 +1,25 @@
## 九、正则表达式
> 原文:[Regular Expressions](https://eloquentjavascript.net/09_regexp.html)
>
> 译者:[飞龙](https://github.com/wizardforcel)
>
> 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
>
> 自豪地采用[谷歌翻译](https://translate.google.cn/)
>
> 部分参考了[《JavaScript 编程精解(第 2 版)》](https://book.douban.com/subject/26707144/)
> 一些人遇到问题时会认为,“我知道了,我会用正则表达式。”现在它们有两个问题了。
>
> Jamie Zawinski
>
> Yuan-Ma said, 'When you cut against the grain of the wood, much strength is needed. When you program against the grain of the problem, much code is needed.'
>
> Master Yuan-Ma《The Book of Programming》
![](img/9-0.jpg)
程序设计工具技术的发展与传播方式是在混乱中不断进化。在此过程中获胜的往往不是优雅或杰出的一方,而是那些瞄准主流市场,并能够填补市场需求的,或者碰巧与另一种成功的技术集成在一起的工具技术。
本章将会讨论正则表达式regular expression这种工具。正则表达式是一种描述字符串数据模式的方法。它们形成了一种小而独立的语言也是 JavaScript 和许多其他语言和系统的一部分。
@ -14,7 +30,7 @@
正则表达式是一种对象类型。我们可以使用两种方法来构造正则表达式:一是使用`RegExp`构造器构造一个正则表达式对象;二是使用斜杠(`/`)字符将模式包围起来,生成一个字面值。
```
```js
let re1 = new RegExp("abc");
let re2 = /abc/;
```
@ -25,7 +41,7 @@ let re2 = /abc/;
第二种写法将模式写在斜杠之间,处理反斜杠的方式与第一种方法略有差别。首先,由于斜杠会结束整个模式,因此模式中包含斜杠时,需在斜杠前加上反斜杠。此外,如果反斜杠不是特殊字符代码(比如`\n`)的一部分,则会保留反斜杠,不像字符串中会将其忽略,也不会改变模式的含义。一些字符,比如问号、加号在正则表达式中有特殊含义,如果你想要表示其字符本身,需要在字符前加上反斜杠。
```
```js
let eighteenPlus = /eighteen\+/;
```
@ -33,7 +49,7 @@ let eighteenPlus = /eighteen\+/;
正则表达式对象有许多方法。其中最简单的就是`test`方法。`test`方法接受用户传递的字符串,并返回一个布尔值,表示字符串中是否包含能与表达式模式匹配的字符串。
```
```js
console.log(/abc/.test("abcde"));
// → true
console.log(/abc/.test("abxde"));
@ -50,7 +66,7 @@ console.log(/abc/.test("abxde"));
下面两个表达式都可以匹配包含数字的字符串。
```
```js
console.log(/[0123456789]/.test("in 1992"));
// → true
console.log(/[0-9]/.test("in 1992"));
@ -77,7 +93,7 @@ console.log(/[0-9]/.test("in 1992"));
因此你可以使用下面的表达式匹配类似于`30-01-2003 15:20`这样的日期数字格式:
```
```js
let dateTime = /\d\d-\d\d-\d\d\d\d \d\d:\d\d/;
console.log(dateTime.test("30-01-2003 15:20"));
// → true
@ -91,7 +107,7 @@ console.log(dateTime.test("30-jan-2003 15:20"));
你可以在左方括号后添加脱字符(`^`)来排除某个字符集,即表示不匹配这组字符中的任何字符。
```
```js
let notBinary = /[^01]/;
console.log(notBinary.test("1100100010100110"));
// → false
@ -105,7 +121,7 @@ console.log(notBinary.test("1100100010200110"));
在正则表达式某个元素后面添加一个加号(`+`),表示该元素至少重复一次。因此`/\d+/`可以匹配一个或多个数字字符。
```
```js
console.log(/'\d+'/.test("'123'"));
// → true
console.log(/'\d+'/.test("''"));
@ -120,7 +136,7 @@ console.log(/'\d*'/.test("''"));
元素后面跟一个问号表示这部分模式“可选”,即模式可能出现 0 次或 1 次。下面的例子可以匹配`neighbour``u`出现1次也可以匹配`neighbor``u`没有出现)。
```
```js
let neighbor = /neighbou?r/;
console.log(neighbor.test("neighbour"));
// → true
@ -132,7 +148,7 @@ console.log(neighbor.test("neighbor"));
这里给出另一个版本的正则表达式,可以匹配日期、月份、小时,每个数字都可以是一位或两位数字。这种形式更易于解释。
```
```js
let dateTime = /\d{1,2}-\d{1,2}-\d{4} \d{1,2}:\d{2}/;
console.log(dateTime.test("30-1-2003 8:45"));
// → true
@ -144,7 +160,7 @@ console.log(dateTime.test("30-1-2003 8:45"));
为了一次性对多个元素使用`*`或者`+`,那么你必须使用圆括号,创建一个分组。对于后面的操作符来说,圆括号里的表达式算作单个元素。
```
```js
let cartoonCrying = /boo+(hoo+)+/i;
console.log(cartoonCrying.test("Boohoooohoohooo"));
// → true
@ -158,7 +174,7 @@ console.log(cartoonCrying.test("Boohoooohoohooo"));
`test`方法是匹配正则表达式最简单的方法。该方法只负责判断字符串是否与某个模式匹配。正则表达式还有一个`exec`执行execute方法如果无法匹配模式则返回`null`,否则返回一个表示匹配字符串信息的对象。
```
```js
let match = /\d+/.exec("one two 100");
console.log(match);
// → ["100"]
@ -170,14 +186,14 @@ console.log(match.index);
字符串也有一个类似的match方法。
```
```js
console.log("one two 100".match(/\d+/));
// → ["100"]
```
若正则表达式包含使用圆括号包围的子表达式分组,与这些分组匹配的文本也会出现在数组中。第一个元素是与整个模式匹配的字符串,其后是与第一个分组匹配的部分字符串(表达式中第一次出现左圆括号的那部分),然后是第二个分组。
```
```js
let quotedText = /'([^']*)'/;
console.log(quotedText.exec("she said 'hello'"));
// → ["'hello'", "hello"]
@ -185,7 +201,7 @@ console.log(quotedText.exec("she said 'hello'"));
若分组最后没有匹配任何字符串(例如在元组后加上一个问号),结果数组中与该分组对应的元素将是`undefined`。类似的,若分组匹配了多个元素,则数组中只包含最后一个匹配项。
```
```js
console.log(/bad(ly)?/.exec("bad"));
// → ["bad", undefined]
console.log(/(\d)+/.exec("123"));
@ -200,14 +216,14 @@ console.log(/(\d)+/.exec("123"));
JavaScript 提供了用于表示日期的标准类,我们甚至可以用其表示时间点。该类型名为`Date`。如果使用`new`创建一个`Date`对象,你会得到当前的日期和时间。
```
```js
console.log(new Date());
// → Mon Nov 13 2017 16:19:11 GMT+0100 (CET)
```
你也可以创建表示特定时间的对象。
```
```js
console.log(new Date(2009, 11, 9));
// → Wed Dec 09 2009 00:00:00 GMT+0100 (CET)
console.log(new Date(2009, 11, 9, 12, 59, 59, 999));
@ -220,7 +236,7 @@ JavaScript 中约定是:使用从 0 开始的数字表示月份(因此使用
时间戳存储为 UTC 时区中 1970 年以来的毫秒数。 这遵循一个由“Unix 时间”设定的约定,该约定是在那个时候发明的。 你可以对 1970 年以前的时间使用负数。 日期对象上的`getTime`方法返回这个数字。 你可以想象它会很大。
```
```js
console.log(new Date(2013, 11, 19).getTime());
// → 1387407600000
console.log(new Date(1387407600000));
@ -233,7 +249,7 @@ console.log(new Date(1387407600000));
通过在希望捕获的那部分模式字符串两边加上圆括号,我们可以从字符串中创建对应的`Date`对象。
```
```js
function getDate(string) {
let [_, day, month, year] =
/(\d{1,2})-(\d{1,2})-(\d{4})/.exec(string);
@ -253,7 +269,7 @@ console.log(getDate("30-1-2003"));
另一方面,如果我们想要确保日期字符串起始结束位置在单词边界上,可以使用`\b`标记。所谓单词边界,指的是起始和结束位置都是单词字符(也就是`\w`代表的字符集合),而起始位置的前一个字符以及结束位置的后一个字符不是单词字符。
```
```js
console.log(/cat/.test("concatenate"));
// → true
console.log(/\bcat\b/.test("concatenate"));
@ -268,7 +284,7 @@ console.log(/\bcat\b/.test("concatenate"));
那么我们可以编写三个正则表达式并轮流测试,但还有一种更好的方式。管道符号(`|`)表示从其左侧的模式和右侧的模式任意选择一个进行匹配。因此代码如下所示。
```
```js
let animalCount = /\b\d+ (pig|cow|chicken)s?\b/;
console.log(animalCount.test("15 pigs"));
// → true
@ -284,7 +300,7 @@ console.log(animalCount.test("15 pigchickens"));
为了进行实际的匹配,引擎会像处理流程图一样处理正则表达式。 这是上例中用于家畜表达式的图表:
![](../Images/00302.jpeg)
![](img/9-1.svg)
如果我们可以找到一条从图表左侧通往图表右侧的路径,则可以说“表达式产生了匹配”。我们保存在字符串中的当前位置,每移动通过一个盒子,就验证当前位置之后的部分字符串是否与该盒子匹配。
@ -306,21 +322,19 @@ console.log(animalCount.test("15 pigchickens"));
正则表达式`/\b([01]+b|\d+|[\da-f]h)\b/`可以匹配三种字符串:以`b`结尾的二进制数字,以`h`结尾的十六进制数字(即以 16 为进制,字母`a``f`表示数字 10 到 15或者没有后缀字符的常规十进制数字。这是对应的图表。
![]()
![](img/9-2.svg)
当匹配该表达式时,常常会发生一种情况:输入的字符串进入上方(二进制)分支的匹配过程,但输入中并不包含二进制数字。我们以匹配字符串`"103"`为例,匹配过程只有遇到字符 3 时才知道进入了错误分支。该字符串匹配我们给出的表达式,但没有匹配目前应当处于的分支。
因此匹配器执行“回溯”。进入一个分支时,匹配器会记住当前位置(在本例中,是在字符串起始,刚刚通过图中第一个表示边界的盒子),因此若当前分支无法匹配,可以回退并尝试另一条分支。对于字符串`"103"`,遇到字符 3 之后,它会开始尝试匹配十六进制数字的分支,它会再次失败,因为数字后面没有`h`。所以它尝试匹配进制数字的分支,由于这条分支可以匹配,因此匹配器最后的会返回十进制数的匹配信息。
![](../Images/00303.jpeg)
一旦字符串与模式完全匹配,匹配器就会停止。这意味着多个分支都可能匹配一个字符串,但匹配器最后只会使用第一条分支(按照出现在正则表达式中的出现顺序排序)。
回溯也会发生在处理重复模式运算符(比如`+``*`)时。如果使用`"abcxe"`匹配`/^.*x/``.*`部分,首先尝试匹配整个字符串,接着引擎发现匹配模式还需要一个字符`x`。由于字符串结尾没有`x`,因此`*`运算符尝试少匹配一个字符。但匹配器依然无法在`abcx`之后找到`x`字符,因此它会再次回溯,此时`*`运算符只匹配`abc`。现在匹配器发现了所需的`x`,接着报告从位置 0 到位置 4 匹配成功。
我们有可能编写需要大量回溯的正则表达式。当模式能够以许多种不同方式匹配输入的一部分时,这种问题就会出现。例如,若我们在编写匹配二进制数字的正则表达式时,一时糊涂,可能会写出诸如`/([01]+)+b/`之类的表达式。
![](../Images/00304.jpeg)
![](img/9-3.svg)
若我们尝试匹配一些只由 0 与 1 组成的长序列,匹配器首先会不断执行内部循环,直到它发现没有数字为止。接下来匹配器注意到,这里不存在`b`,因此向前回溯一个位置,开始执行外部循环,接着再次放弃,再次尝试执行一次内部循环。该过程会尝试这两个循环的所有可能路径。这意味着每多出一个字符,其工作量就会加倍。甚至只需较少的一堆字符,就可使匹配实际上永不停息地执行下去。
@ -328,14 +342,14 @@ console.log(animalCount.test("15 pigchickens"));
字符串有一个`replace`方法,该方法可用于将字符串中的一部分替换为另一个字符串。
```
```js
console.log("papa".replace("p", "m"));
// → mapa
```
该方法第一个参数也可以是正则表达式,这种情况下会替换正则表达式首先匹配的部分字符串。若在正则表达式后追加`g`选项全局Global该方法会替换字符串中所有匹配项而不是只替换第一个。
```
```js
console.log("Borobudur".replace(/[ou]/, "a"));
// → Barobudur
console.log("Borobudur".replace(/[ou]/g, "a"));
@ -346,7 +360,7 @@ console.log("Borobudur".replace(/[ou]/g, "a"));
如果我们在替换字符串中使用元组,就可以体现出`replace`方法的真实威力。例如,假设我们有一个规模很大的字符串,包含了人的名字,每个名字占据一行,名字格式为“姓,名”。若我们想要交换姓名,并移除中间的逗号(转变成“名,姓”这种格式),我们可以使用下面的代码:
```
```js
console.log(
"Liskov, Barbara\nMcCarthy, John\nWadler, Philip"
.replace(/(\w+), (\w+)/g, "$2 $1"));
@ -361,7 +375,7 @@ console.log(
这里给出一个小示例:
```
```js
let s = "the cia and fbi";
console.log(s.replace(/\b(fbi|cia)\b/g,
str => str.toUpperCase()));
@ -370,7 +384,7 @@ console.log(s.replace(/\b(fbi|cia)\b/g,
这里给出另一个值得讨论的示例:
```
```js
let stock = "1 lemon, 2 cabbages, and 101 eggs";
function minusOne(match, amount, unit) {
amount = Number(amount) - 1;
@ -393,7 +407,7 @@ console.log(stock.replace(/(\d+) (\w+)/g, minusOne));
使用`replace`编写一个函数移除 JavaScript 代码中的所有注释也是可能的。这里我们尝试一下:
```
```js
function stripComments(code) {
return code.replace(/\/\/.*|\/\*[^]*\*\//g, "");
}
@ -417,7 +431,7 @@ console.log(stripComments("1 /* a */+/* b */ 1"));
而这便是我们想要的情况。通过让星号尽量少地匹配字符,我们可以匹配第一个`*/`,进而匹配一个块注释,而不会匹配过多内容。
```
```js
function stripComments(code) {
return code.replace(/\/\/.*|\/\*[^]*?\*\//g, "");
}
@ -435,7 +449,7 @@ console.log(stripComments("1 /* a */+/* b */ 1"));
这里给出一个示例。
```
```js
let name = "harry";
let text = "Harry is a suspicious character.";
let regexp = new RegExp("\\b(" + name + ")\\b", "gi");
@ -449,7 +463,7 @@ console.log(text.replace(regexp, "_$1_"));
为了能够处理这种情况,我们可以在任何有特殊含义的字符前添加反斜杠。
```
```js
let name = "dea+hl[]rd";
let text = "This dea+hl[]rd guy is super annoying.";
let escaped = name.replace(/[^\w\s]/g, "\\$&");
@ -464,7 +478,7 @@ console.log(text.replace(regexp, "_><_"));
但还有一个`search`方法,调用该方法时需要传递一个正则表达式。类似于`indexOf`,该方法会返回首先匹配的表达式的索引,若没有找到则返回 1。
```
```js
console.log(" word".search(/\S/));
// → 2
console.log(" ".search(/\S/));
@ -481,7 +495,7 @@ console.log(" ".search(/\S/));
所谓的极少数情况,指的是当正则表达式启用了全局(`g`)或者粘性(`y`),并且使用`exec`匹配模式的时候。此外,另一个解决方案应该是向`exec`传递的额外参数,但 JavaScript 的正则表达式接口能设计得如此合理才是怪事。
```
```js
let pattern = /y/g;
pattern.lastIndex = 3;
let match = pattern.exec("xyzzy");
@ -495,7 +509,7 @@ console.log(pattern.lastIndex);
全局和粘性选项之间的区别在于,启用粘性时,仅当匹配直接从`lastIndex`开始时,搜索才会成功,而全局搜索中,它会搜索匹配可能起始的所有位置。
```
```js
let global = /abc/g;
console.log(global.exec("xyz abc"));
// → ["abc"]
@ -506,7 +520,7 @@ console.log(sticky.exec("xyz abc"));
对多个`exec`调用使用共享的正则表达式值时,这些`lastIndex`属性的自动更新可能会导致问题。 你的正则表达式可能意外地在之前的调用留下的索引处开始。
```
```js
let digit = /\d/g;
console.log(digit.exec("here it is: 1"));
// → ["1"]
@ -516,7 +530,7 @@ console.log(digit.exec("and now: 1"));
全局选项还有一个值得深思的效果,它会改变`match`匹配字符串的工作方式。如果调用`match`时使用了全局表达式,不像`exec`返回的数组,`match`会找出所有匹配模式的字符串,并返回一个包含所有匹配字符串的数组。
```
```js
console.log("Banana".match(/an/g));
// → ["an", "an"]
```
@ -527,7 +541,7 @@ console.log("Banana".match(/an/g));
一个常见的事情是,找出字符串中所有模式的出现位置,这种情况下,我们可以在循环中使用`lastIndex``exec`访问匹配的对象。
```
```js
let input = "A string with 3 numbers in it... 42 and 88.";
let number = /\b(\d+)\b/g;
let match;
@ -576,7 +590,7 @@ outputdir=/home/marijn/enemies/davaeorn
由于我们需要逐行处理这种格式的文件,因此预处理时最好将文件分割成一行行文本。我们使用第 6 章中的`string.split("\n")`来分割文件内容。但是一些操作系统并非使用换行符来分隔行,而是使用回车符加换行符(`"\r\n"`)。考虑到这点,我们也可以使用正则表达式作为`split`方法的参数,我们使用类似于`/\r?\n/`的正则表达式,这样可以同时支持`"\n"``"\r\n"`两种分隔符。
```
```js
function parseINI(string) {
// Start with an object to hold the top-level fields
let currentSection = {name: null, fields: []};
@ -618,7 +632,7 @@ city=Tessaloniki`));
另一个问题是,默认情况下,正则表达式使用代码单元,而不是实际的字符,正如第 5 章中所讨论的那样。 这意味着由两个代码单元组成的字符表现很奇怪。
```
```js
console.log(/\ud83c\udf4e{3}/.test("\ud83c\udf4e\ud83c\udf4e\ud83c\udf4e"));
// → false
console.log(/<.>/.test("<\ud83c\udf39>"));
@ -633,7 +647,7 @@ console.log(/<.>/u.test("<\ud83c\udf39>"));
尽管这是刚刚标准化的,在撰写本文时尚未得到广泛支持,但可以在正则表达式中使用`\p`(必须启用 Unicode 选项)以匹配 Unicode 标准分配了给定属性的所有字符。
```
```js
console.log(/\p{Script=Greek}/u.test("α"));
// → true
console.log(/\p{Script=Arabic}/u.test("α"));
@ -720,7 +734,7 @@ Code Golf 是一种游戏,尝试尽量用最少的字符来描述特定程序
需要帮助时,请参考本章总结中的表格。使用少量测试字符串来测试每个解决方案。
```
```js
// Fill in the regular expressions
verify(/.../,
@ -770,7 +784,7 @@ function verify(regexp, yes, no) {
思考一下可以区分这两种引号用法的模式,并手动调用`replace`方法进行正确替换。
```
```js
let text = "'I'm the cook,' he said, 'it's my job.'";
// Change this call.
console.log(text.replace(/A/g, "B"));
@ -781,7 +795,7 @@ console.log(text.replace(/A/g, "B"));
编写一个表达式,只匹配 JavaScript 风格的数字。支持数字前可选的正号与负号、十进制小数点、指数计数法(`5e-3``1E10`,指数前也需要支持可选的符号)。也请注意小数点前或小数点后的数字也是不必要的,但数字不能只有小数点。例如`.5``5.`都是合法的 JavaScript 数字,但单个点则不是。
```
```js
// Fill in this regular expression.
let number = /^...$/;

BIN
img/9-0.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

307
img/9-1.svg Normal file
View File

@ -0,0 +1,307 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
height="166.23486"
version="1.1"
width="618.75934">
<path
d="m 502.86787,89.225694 h 13.16396"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path4"/>
<path
d="m 405.45455,89.225694 h 13.16396"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path6"/>
<path
d="M 234.32304,89.225694 H 247.487"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path8"/>
<path
d="m 193.51476,89.225694 h 13.16396"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path10"/>
<path
d="m 110.5818,89.225694 h 13.16396"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path12"/>
<path
d="m 418.61851,89.225694 q 13.16396,0 13.16396,-13.16396 v -3.290991 q 0,-13.163962 13.16396,-13.163962 h 31.59351 q 13.16396,0 13.16396,13.163962 v 3.290991 q 0,13.16396 13.16397,13.16396"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path14"/>
<path
d="M 502.86787,89.225694 H 476.53994"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path16"/>
<path
d="m 418.61851,89.225694 h 26.32792"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path18"/>
<path
d="M 405.45455,89.225694 H 392.29059"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path20"/>
<path
d="m 247.487,89.225694 h 13.16396"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path22"/>
<path
d="m 392.29059,89.225694 q -13.16397,0 -13.16397,13.163956 v 19.74595 q 0,13.16396 -13.16396,13.16396 h 0"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path24"/>
<path
d="m 260.65096,89.225694 q 13.16397,0 13.16397,13.163956 v 19.74595 q 0,13.16396 13.16396,13.16396 h 0"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path26"/>
<path
d="m 392.29059,89.225694 c -13.16397,0 -13.16397,0 -39.49189,0"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path28"/>
<path
d="m 260.65096,89.225694 c 13.16397,0 13.16397,0 39.49189,0"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path30"/>
<path
d="m 392.29059,89.225694 q -13.16397,0 -13.16397,-13.16396 V 56.31579 q 0,-13.163962 -13.16396,-13.163962 h -16.45495"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path32"/>
<path
d="m 260.65096,89.225694 q 13.16397,0 13.16397,-13.16396 V 56.31579 q 0,-13.163962 13.16396,-13.163962 h 16.45495"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path34"/>
<path
d="m 180.3508,89.225694 q 13.16396,0 13.16396,13.163956 v 3.29099 q 0,13.16397 -13.16396,13.16397 h -43.44108 q -13.16396,0 -13.16396,-13.16397 v -3.29099 q 0,-13.163956 13.16396,-13.163956"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path36"/>
<path
d="M 193.51476,89.225694 H 180.3508"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path38"/>
<path
d="m 123.74576,89.225694 h 13.16396"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path40"/>
<desc
id="desc42">Created with Raphaël 2.1.0</desc>
<defs
id="defs44" />
<rect
x="206.67871"
y="72.770744"
width="27.64432"
height="32.909904"
r="0"
rx="3.9491887"
ry="3.9491887"
style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.31639624"
id="rect46" />
<text
x="220.50089"
y="89.225693"
font="10px &quot;Arial&quot;"
style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text48">
<tspan
dy="5.9237828"
id="tspan50">&quot; &quot;</tspan>
</text>
<rect
x="21.562796"
y="72.66703"
width="89.122711"
height="33.117336"
r="0"
rx="2.7850847"
ry="3.974081"
style="fill:#bada55;stroke:#bada55;stroke-width:1.10896111"
id="rect52" />
<text
x="47.394775"
y="89.225693"
font="10px &quot;Arial&quot;"
style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text54">
<tspan
id="tspan56"></tspan>
</text>
<text
x="66.728333"
y="94.361168"
font="10px &quot;Arial&quot;"
style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text3087">
<tspan
id="tspan3089">boundary</tspan>
</text>
<rect
x="515.90363"
y="72.642578"
width="81.317352"
height="33.166233"
r="0"
rx="2.5411673"
ry="3.979948"
style="fill:#bada55;stroke:#bada55;stroke-width:1.06006885"
id="rect58" />
<text
x="556.56232"
y="94.663254"
font="10px &quot;Arial&quot;"
style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text60">
<tspan
id="tspan62">boundary</tspan>
</text>
<rect
x="247.487"
y="13.532914"
width="157.96754"
height="151.38556"
r="0"
rx="3.9491887"
ry="3.9491887"
style="fill:none;stroke:#a0a0a0;stroke-width:2.63279247;stroke-dasharray:7.89837727, 2.63279242"
id="rect64" />
<text
x="276.44772"
y="4.9763379"
font="10px &quot;Arial&quot;"
style="font-size:13.16396236px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="10px"
id="text66">
<tspan
dy="4.6073866"
id="tspan68">Group #1</tspan>
</text>
<rect
x="286.97888"
y="118.8446"
width="78.983772"
height="32.909904"
r="0"
rx="3.9491887"
ry="3.9491887"
style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.31639624"
id="rect70" />
<text
x="326.47076"
y="135.29956"
font="10px &quot;Arial&quot;"
style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text72">
<tspan
dy="5.9237828"
id="tspan74">&quot;chicken&quot;</tspan>
</text>
<rect
x="300.14285"
y="72.770744"
width="52.655849"
height="32.909904"
r="0"
rx="3.9491887"
ry="3.9491887"
style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.31639624"
id="rect76" />
<text
x="326.47076"
y="89.225693"
font="10px &quot;Arial&quot;"
style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text78">
<tspan
dy="5.9237828"
id="tspan80">&quot;cow&quot;</tspan>
</text>
<rect
x="303.43384"
y="26.696877"
width="46.073868"
height="32.909904"
r="0"
rx="3.9491887"
ry="3.9491887"
style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.31639624"
id="rect82" />
<text
x="326.47076"
y="43.151829"
font="10px &quot;Arial&quot;"
style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text84">
<tspan
dy="5.9237828"
id="tspan86">&quot;pig&quot;</tspan>
</text>
<rect
x="136.90971"
y="72.770744"
width="43.441074"
height="32.909904"
r="0"
rx="3.9491887"
ry="3.9491887"
style="fill:#bada55;stroke:#bada55;stroke-width:1.31639624"
id="rect88" />
<text
x="158.63025"
y="89.225693"
font="10px &quot;Arial&quot;"
style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text90">
<tspan
dy="5.9237828"
id="tspan92">digit</tspan>
</text>
<rect
x="444.94644"
y="72.770744"
width="31.59351"
height="32.909904"
r="0"
rx="3.9491887"
ry="3.9491887"
style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.31639624"
id="rect94" />
<text
x="460.74319"
y="89.225693"
font="10px &quot;Arial&quot;"
style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text96">
<tspan
dy="5.9237828"
id="tspan98">&quot;s&quot;</tspan>
</text>
<path
d="M 7.8983762,89.225694 H 21.062338"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path100"/>
<circle
cx="10"
cy="80.5"
r="5"
style="fill:#6b6659;stroke:#000000;stroke-width:2"
id="circle102"
transform="matrix(1.3163962,0,0,1.3163962,-5.2655848,-16.744199)" />
<path
d="M 610.86099,88.62152 H 597.69703"
style="fill:none;stroke:#000000;stroke-width:2.63279247"
id="path104"/>
<circle
cx="530"
cy="80.5"
r="5"
style="fill:#6b6659;stroke:#000000;stroke-width:2"
id="circle106"
transform="matrix(1.3163962,0,0,1.3163962,-86.82901,-17.348373)" />
</svg>

After

Width:  |  Height:  |  Size: 9.7 KiB

72
img/9-2.svg Normal file
View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" version="1.1" width="578" height="342">
<defs>
<style type="text/css">svg {
background-color: #fff; }
.root text,
.root tspan {
font: 12px Arial; }
.root path {
fill-opacity: 0;
stroke-width: 2px;
stroke: #000; }
.root circle {
fill: #6b6659;
stroke-width: 2px;
stroke: #000; }
.anchor text, .any-character text {
fill: #fff; }
.anchor rect, .any-character rect {
fill: #6b6659; }
.escape text, .charset-escape text, .literal text {
fill: #000; }
.escape rect, .charset-escape rect {
fill: #bada55; }
.literal rect {
fill: #dae9e5; }
.charset .charset-box {
fill: #cbcbba; }
.subexp .subexp-label tspan,
.charset .charset-label tspan,
.match-fragment .repeat-label tspan {
font-size: 10px; }
.repeat-label {
cursor: help; }
.subexp .subexp-label tspan,
.charset .charset-label tspan {
dominant-baseline: text-after-edge; }
.subexp .subexp-box {
stroke: #908c83;
stroke-dasharray: 6,2;
stroke-width: 2px;
fill-opacity: 0; }
.quote {
fill: #908c83; }
</style>
</defs>
<metadata>
<rdf:rdf>
<cc:license rdf:about="http://creativecommons.org/licenses/by/3.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"></cc:permits>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"></cc:permits>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"></cc:requires>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"></cc:requires>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"></cc:permits>
</cc:license>
</rdf:rdf>
</metadata>
<desc>Created with Snap</desc><g class="root" transform="matrix(1.3,0,0,1.3,15,10)"><g class="regexp match" transform="matrix(1,0,0,1,10,0)"><path d="M92,127H112M282,127H302"></path><g class="match-fragment escape" transform="matrix(1,0,0,1,0,115)"><g class="label"><rect width="92" height="24" rx="3" ry="3"></rect><text x="0" y="0" transform="matrix(1,0,0,1,5,17)"><tspan>word boundary</tspan></text></g></g><g class="match-fragment subexp" transform="matrix(1,0,0,1,102,0)"><rect class="subexp-box" rx="3" ry="3" transform="matrix(1,0,0,1,0,11)" width="190" height="232"></rect><text x="0" y="0" class="subexp-label" transform="matrix(1,0,0,1,0,11)"><tspan>group #1</tspan></text><g class="regexp" transform="matrix(1,0,0,1,10,21)"><path d="M10,52.5q0,-10 10,-10M160,52.5q0,-10 -10,-10M10,121.5q0,10 10,10M160,121.5q0,10 -10,10M10,180q0,10 10,10M160,180q0,10 -10,10M0,106q10,0 10,-10V52.5M170,106q-10,0 -10,-10V52.5M0,106q10,0 10,10V180M170,106q-10,0 -10,10V180"></path><g class="regexp-matches" transform="matrix(1,0,0,1,20,0)"><path d="M0,42.5h27.5M112.5,42.5H130M0,131.5h10M130,131.5H130M0,190h46M79,190H130"></path><g class="match" transform="matrix(1,0,0,1,17.5,0)"><path d="M45,42.5H70"></path><g class="match-fragment" transform="matrix(1,0,0,1,0,0)"><path d="M10,42.5q-10,0 -10,10v21.5q0,10 10,10h35q10,0 10,-10v-21.5q0,-10 -10,-10M55,57.5l5,-5m-5,5l-5,-5"></path><g class="charset" transform="matrix(1,0,0,1,10,0)"><rect class="charset-box" rx="3" ry="3" transform="matrix(1,0,0,1,0,11)" width="35" height="63"></rect><text x="0" y="0" class="charset-label" transform="matrix(1,0,0,1,0,11)"><tspan>One of:</tspan></text><g transform="matrix(1,0,0,1,5,16)"><g class="literal" transform="matrix(1,0,0,1,0,0)"><g class="label"><rect width="25" height="24" rx="3" ry="3"></rect><text x="0" y="0" transform="matrix(1,0,0,1,5,17)"><tspan class="quote"></tspan><tspan>0</tspan><tspan class="quote"></tspan></text></g></g><g class="literal" transform="matrix(1,0,0,1,0,29)"><g class="label"><rect width="25" height="24" rx="3" ry="3"></rect><text x="0" y="0" transform="matrix(1,0,0,1,5,17)"><tspan class="quote"></tspan><tspan>1</tspan><tspan class="quote"></tspan></text></g></g></g></g></g><g class="match-fragment literal" transform="matrix(1,0,0,1,70,30.5)"><g class="label"><rect width="25" height="24" rx="3" ry="3"></rect><text x="0" y="0" transform="matrix(1,0,0,1,5,17)"><tspan class="quote"></tspan><tspan>b</tspan><tspan class="quote"></tspan></text></g></g></g><g class="match" transform="matrix(1,0,0,1,0,89)"><path d="M80,42.5H105"></path><g class="match-fragment" transform="matrix(1,0,0,1,0,0)"><path d="M10,42.5q-10,0 -10,10v21.5q0,10 10,10h70q10,0 10,-10v-21.5q0,-10 -10,-10M90,57.5l5,-5m-5,5l-5,-5"></path><g class="charset" transform="matrix(1,0,0,1,10,0)"><rect class="charset-box" rx="3" ry="3" transform="matrix(1,0,0,1,0,11)" width="70" height="63"></rect><text x="0" y="0" class="charset-label" transform="matrix(1,0,0,1,0,11)"><tspan>One of:</tspan></text><g transform="matrix(1,0,0,1,5,16)"><g class="charset-escape" transform="matrix(1,0,0,1,13.5,0)"><g class="label"><rect width="33" height="24" rx="3" ry="3"></rect><text x="0" y="0" transform="matrix(1,0,0,1,5,17)"><tspan>digit</tspan></text></g></g><g class="charset-range" transform="matrix(1,0,0,1,0,29)"><text x="0" y="0" transform="matrix(1,0,0,1,30,16)">-</text><g class="literal" transform="matrix(1,0,0,1,0,0)"><g class="label"><rect width="25" height="24" rx="3" ry="3"></rect><text x="0" y="0" transform="matrix(1,0,0,1,5,17)"><tspan class="quote"></tspan><tspan>a</tspan><tspan class="quote"></tspan></text></g></g><g class="literal" transform="matrix(1,0,0,1,39,0)"><g class="label"><rect width="21" height="24" rx="3" ry="3"></rect><text x="0" y="0" transform="matrix(1,0,0,1,5,17)"><tspan class="quote"></tspan><tspan>f</tspan><tspan class="quote"></tspan></text></g></g></g></g></g></g><g class="match-fragment literal" transform="matrix(1,0,0,1,105,30.5)"><g class="label"><rect width="25" height="24" rx="3" ry="3"></rect><text x="0" y="0" transform="matrix(1,0,0,1,5,17)"><tspan class="quote"></tspan><tspan>h</tspan><tspan class="quote"></tspan></text></g></g></g><g class="match match-fragment" transform="matrix(1,0,0,1,36,178)"><path d="M10,12q-10,0 -10,10v2q0,10 10,10h33q10,0 10,-10v-2q0,-10 -10,-10M53,27l5,-5m-5,5l-5,-5"></path><g class="escape" transform="matrix(1,0,0,1,10,0)"><g class="label"><rect width="33" height="24" rx="3" ry="3"></rect><text x="0" y="0" transform="matrix(1,0,0,1,5,17)"><tspan>digit</tspan></text></g></g></g></g></g></g><g class="match-fragment escape" transform="matrix(1,0,0,1,302,115)"><g class="label"><rect width="92" height="24" rx="3" ry="3"></rect><text x="0" y="0" transform="matrix(1,0,0,1,5,17)"><tspan>word boundary</tspan></text></g></g></g><path d="M10,127H0M404,127H414"></path><circle cx="0" cy="127" r="5"></circle><circle cx="414" cy="127" r="5"></circle></g></svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

175
img/9-3.svg Normal file
View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
height="180.30476"
version="1.1"
width="217.52544">
<path
d="m 149.04519,91.683302 h 13.4275"
style="fill:none;stroke:#000000;stroke-width:2.68549919"
id="path4"/>
<path
d="m 135.6177,91.683302 q 13.42749,0 13.42749,13.427498 v 60.42373 q 0,13.42749 -13.42749,13.42749 H 34.911488 q -13.427496,0 -13.427496,-13.42749 V 105.1108 q 0,-13.427498 13.427496,-13.427498"
style="fill:none;stroke:#000000;stroke-width:2.68549919"
id="path6"/>
<path
d="M 149.04519,91.683302 H 135.6177"
style="fill:none;stroke:#000000;stroke-width:2.68549919"
id="path8"/>
<path
d="M 21.483992,91.683302 H 34.911488"
style="fill:none;stroke:#000000;stroke-width:2.68549919"
id="path10"/>
<path
d="M 135.6177,91.683302 H 122.1902"
style="fill:none;stroke:#000000;stroke-width:2.68549919"
id="path12"/>
<path
d="M 34.911488,91.683302 H 48.338983"
style="fill:none;stroke:#000000;stroke-width:2.68549919"
id="path14"/>
<path
d="m 108.76272,91.683302 q 13.42748,0 13.42748,13.427498 v 33.56873 q 0,13.4275 -13.42748,13.4275 H 61.766478 q -13.427495,0 -13.427495,-13.4275 V 105.1108 q 0,-13.427498 13.427495,-13.427498"
style="fill:none;stroke:#000000;stroke-width:2.68549919"
id="path16"/>
<path
d="M 122.1902,91.683302 H 108.76272"
style="fill:none;stroke:#000000;stroke-width:2.68549919"
id="path18"/>
<path
d="M 48.338983,91.683302 H 61.766478"
style="fill:none;stroke:#000000;stroke-width:2.68549919"
id="path20"/>
<desc
id="desc22">Created with Raphaël 2.1.0</desc>
<defs
id="defs24" />
<rect
x="162.4727"
y="74.898933"
width="33.568737"
height="33.568737"
r="0"
rx="4.0282488"
ry="4.0282488"
style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.3427496"
id="rect26" />
<text
x="179.25706"
y="91.683304"
font="10px &quot;Arial&quot;"
style="font-size:16.11299515px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text28">
<tspan
dy="6.0423727"
id="tspan30">&quot;b&quot;</tspan>
</text>
<rect
x="34.911488"
y="13.803831"
width="100.70621"
height="151.7307"
r="0"
rx="4.0282488"
ry="4.0282488"
style="fill:none;stroke:#a0a0a0;stroke-width:2.68549919;stroke-dasharray:8.05649719, 2.68549906"
id="rect32" />
<text
x="64.451981"
y="5.0759606"
font="10px &quot;Arial&quot;"
style="font-size:13.427495px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="10px"
id="text34">
<tspan
dy="4.6996231"
id="tspan36">Group #1</tspan>
</text>
<rect
x="61.766479"
y="44.687069"
width="46.996235"
height="93.99247"
r="0"
rx="4.0282488"
ry="4.0282488"
style="fill:#cbcbba;stroke:#cbcbba;stroke-width:1.3427496"
id="rect38" />
<text
x="85.264595"
y="35.959198"
font="10px &quot;Arial&quot;"
style="font-size:13.427495px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="10px"
id="text40">
<tspan
dy="4.6996231"
id="tspan42">One of:</tspan>
</text>
<rect
x="68.480232"
y="98.397057"
width="33.568737"
height="33.568737"
r="0"
rx="4.0282488"
ry="4.0282488"
style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.3427496"
id="rect44" />
<text
x="85.264595"
y="115.18143"
font="10px &quot;Arial&quot;"
style="font-size:16.11299515px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text46">
<tspan
dy="6.0423727"
id="tspan48">&quot;1&quot;</tspan>
</text>
<rect
x="68.480232"
y="51.400818"
width="33.568737"
height="33.568737"
r="0"
rx="4.0282488"
ry="4.0282488"
style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.3427496"
id="rect50" />
<text
x="85.264595"
y="68.185188"
font="10px &quot;Arial&quot;"
style="font-size:16.11299515px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial"
font-size="12px"
id="text52">
<tspan
dy="6.0423727"
id="tspan54">&quot;0&quot;</tspan>
</text>
<path
d="M 8.0564968,91.683302 H 21.483992"
style="fill:none;stroke:#000000;stroke-width:2.68549919"
id="path56"/>
<circle
cx="10"
cy="81"
r="5"
style="fill:#6b6659;stroke:#000000;stroke-width:2"
id="circle58"
transform="matrix(1.3427496,0,0,1.3427496,-5.3709984,-17.079408)" />
<path
d="M 209.46892,91.683302 H 196.04143"
style="fill:none;stroke:#000000;stroke-width:2.68549919"
id="path60"/>
<circle
cx="160"
cy="81"
r="5"
style="fill:#6b6659;stroke:#000000;stroke-width:2"
id="circle62"
transform="matrix(1.3427496,0,0,1.3427496,-5.3709984,-17.079408)" />
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB