85.md 21.4 KB
Newer Older
W
wizardforcel 已提交
1 2 3 4 5 6
# Ruby 正则表达式

> 原文: [https://zetcode.com/lang/rubytutorial/regex/](https://zetcode.com/lang/rubytutorial/regex/)

在 Ruby 教程的这一部分中,我们将讨论 Ruby 中的正则表达式。

W
wizardforcel 已提交
7
正则表达式用于文本搜索和更高级的文本操作。 正则表达式内置在`grep``sed`等工具中; 诸如 vi,emacs 之类的文本编辑器; Tcl,Perl,Python 等编程语言。 Ruby 也有对正则表达式的内置支持。
W
wizardforcel 已提交
8 9 10 11 12 13 14

从另一个角度来看,正则表达式语法构成了用于匹配文本的特定于域的语言。

模式是一个正则表达式,用于定义我们正在搜索或操纵的文本。 它由文本文字和元字符组成。 该模式放置在两个定界符内。 在 Ruby 中,这些是`//`字符。 它们通知正则表达式函数模式的开始和结束位置。

以下是部分元字符列表:

W
wizardforcel 已提交
15 16
| | |
| --- | --- |
W
wizardforcel 已提交
17 18 19 20 21 22
| `.` | 匹配任何单个字符。 |
| `*` | 与前面的元素匹配零次或多次。 |
| `[ ]` | 括号表达。 与方括号内的字符匹配。 |
| `[^ ]` | 匹配方括号中未包含的单个字符。 |
| `^` | 匹配字符串中的起始位置。 |
| `$` | 匹配字符串中的结束位置。 |
W
wizardforcel 已提交
23
| <code>&#124;</code> | 备用运算符。 |
W
wizardforcel 已提交
24

W
wizardforcel 已提交
25
`=~`运算符将正则表达式与字符串进行匹配,如果找到匹配项,则返回匹配项与字符串的偏移量,否则返回`nil``Regexp`类用于开发正则表达式。 还有两种创建正则表达式的简便方法。 以下示例将显示它们。
W
wizardforcel 已提交
26

W
wizardforcel 已提交
27
```ruby
W
wizardforcel 已提交
28 29 30 31 32 33 34 35 36 37 38 39
#!/usr/bin/ruby

re = Regexp.new 'Jane'
p "Jane is hot".match re

p "Jane is hot" =~ /Jane/
p "Jane is hot".match %r{Jane}

```

在第一个示例中,我们展示了在字符串上应用正则表达式的三种方式。

W
wizardforcel 已提交
40
```ruby
W
wizardforcel 已提交
41 42 43 44 45
re = Regexp.new 'Jane'
p "Jane is hot".match re

```

W
wizardforcel 已提交
46
在以上两行中,我们创建一个`Regexp`对象,其中包含一个简单的正则表达式文本。 使用`match`方法,我们将此正则表达式对象应用于`"Jane is hot"`句子。 我们检查句子中是否包含`"Jane"`一词。
W
wizardforcel 已提交
47

W
wizardforcel 已提交
48
```ruby
W
wizardforcel 已提交
49 50 51 52 53
p "Jane is hot" =~ /Jane/
p "Jane is hot".match %r{Jane}

```

W
wizardforcel 已提交
54
这两行是相同的。 两个正斜杠//和% r {}字符是更冗长的第一种方式的简写。 在本教程中,我们将使用正斜杠。 这是许多语言的事实上的标准。
W
wizardforcel 已提交
55

W
wizardforcel 已提交
56
```ruby
W
wizardforcel 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69
$ ./regex.rb
#<MatchData "Jane">
0
#<MatchData "Jane">

```

在所有三种情况下,都有一个匹配项。 `match`方法返回匹配的数据,如果不匹配,则返回`nil``=~`运算符返回匹配文本的第一个字符,否则返回`nil`

## 点字符

点字符是正则表达式字符,可与任何单个字符匹配。 请注意,必须有一些字符。 它可能不会被省略。

W
wizardforcel 已提交
70
```ruby
W
wizardforcel 已提交
71 72 73 74 75 76 77 78 79 80 81
#!/usr/bin/ruby

p "Seven".match /.even/
p "even".match /.even/
p "eleven".match /.even/
p "proven".match /.even/

```

在第一个示例中,我们将使用`match`方法对字符串应用正则表达式。 `match`方法成功返回匹配的数据,否则返回`nil`

W
wizardforcel 已提交
82
```ruby
W
wizardforcel 已提交
83 84 85 86
p "Seven".match /.even/

```

W
wizardforcel 已提交
87
`"Seven"`是我们称为`match`方法的字符串。 该方法的参数是模式。 `/.even/`常规模式查找以任意字符开头,后跟`"even"`字符的文本。
W
wizardforcel 已提交
88

W
wizardforcel 已提交
89
```ruby
W
wizardforcel 已提交
90 91 92 93 94 95 96 97 98 99
$ ./dot.rb
#<MatchData "Seven">
nil
#<MatchData "leven">
nil

```

从输出中,我们可以看到哪些字符串匹配,哪些不匹配。

W
wizardforcel 已提交
100
就像我们上面说过的,如果有一个点字符,那么必须有一个任意字符。 不可省略。 如果我们要搜索可能会省略字符的文本怎么办? 换句话说,我们想要一个既有`"Seven"`又有`"even"`的模式。 为此,我们可以使用`?`重复字符。 `?`重复字符表明前一个字符可能出现 0 次或 1 次。
W
wizardforcel 已提交
101

W
wizardforcel 已提交
102
```ruby
W
wizardforcel 已提交
103 104 105 106 107 108 109 110 111 112
#!/usr/bin/ruby

p "seven".match /.even/
p "even".match /.even/
p "even".match /.?even/

```

该脚本使用`?`重复字符。

W
wizardforcel 已提交
113
```ruby
W
wizardforcel 已提交
114 115 116 117
p "even".match /.even/

```

W
wizardforcel 已提交
118
该行打印`nil`,因为正则表达式期望在`"even"`字符串之前有一个字符。
W
wizardforcel 已提交
119

W
wizardforcel 已提交
120
```ruby
W
wizardforcel 已提交
121 122 123 124 125 126
p "even".match /.?even/

```

在这里,我们对正则表达式进行了一些修改。 `.?`代表无字符或一个任意字符。 这次有一场比赛。

W
wizardforcel 已提交
127
```ruby
W
wizardforcel 已提交
128 129 130 131 132 133 134 135 136 137 138
$ ./dot2.rb
#<MatchData "seven">
nil
#<MatchData "even">

```

这是示例输出。

## Ruby 正则表达式方法

W
wizardforcel 已提交
139
在前两个示例中,我们使用`match`方法处理正则表达式。 除了`match`以外,其他方法也接受正则表达式作为参数。
W
wizardforcel 已提交
140

W
wizardforcel 已提交
141
```ruby
W
wizardforcel 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155
#!/usr/bin/ruby

puts "motherboard" =~ /board/
puts "12, 911, 12, 111"[/\d{3}/]

puts "motherboard".gsub /board/, "land"

p "meet big deep nil need".scan /.[e][e]./
p "This is Sparta!".split(/\s/)

```

该示例显示了一些可用于正则表达式的方法。

W
wizardforcel 已提交
156
```ruby
W
wizardforcel 已提交
157 158 159 160 161 162
puts "motherboard" =~ /board/

```

`=~`是一个运算符,将右侧的正则表达式应用于左侧的字符串。

W
wizardforcel 已提交
163
```ruby
W
wizardforcel 已提交
164 165 166 167 168 169
puts "12, 911, 12, 111"[/\d{3}/]

```

可以在字符串后的方括号之间放置正则表达式。 该行将打印第一个包含三位数的字符串。

W
wizardforcel 已提交
170
```ruby
W
wizardforcel 已提交
171 172 173 174 175 176
puts "motherboard".gsub /board/, "land"

```

使用`gsub`方法,我们将'board'字符串替换为'land'字符串。

W
wizardforcel 已提交
177
```ruby
W
wizardforcel 已提交
178 179 180 181 182 183
p "meet big deep nil need".scan /.[e][e]./

```

`scan`方法在字符串中查找匹配项。 它查找所有事件,而不仅仅是第一次。 该行将打印所有与模式匹配的字符串。

W
wizardforcel 已提交
184
```ruby
W
wizardforcel 已提交
185 186 187 188 189 190
p "This is Sparta!".split(/\s/)

```

`split`方法使用给定的正则表达式作为分隔符来拆分字符串。 `\s`字符类型代表任何空白字符。

W
wizardforcel 已提交
191
```ruby
W
wizardforcel 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
$ ./apply.rb
6
911
motherland
["meet", "deep", "need"]
["This", "is", "Sparta!"]

```

我们看到`apply.rb`脚本的输出。

## Ruby 特殊变量

使用正则表达式的某些方法会激活一些特殊变量。 它们包含最后一个匹配的字符串,最后一个匹配之前的字符串和最后一个匹配之后的字符串。 这些变量使程序员的工作更加轻松。

W
wizardforcel 已提交
207
```ruby
W
wizardforcel 已提交
208 209 210 211 212 213 214 215 216 217 218 219
#!/usr/bin/ruby

puts "Her name is Jane" =~ /name/

p $`
p $&
p $'

```

该示例显示了三个特殊变量。

W
wizardforcel 已提交
220
```ruby
W
wizardforcel 已提交
221 222 223 224
puts "Her name is Jane" =~ /name/

```

W
wizardforcel 已提交
225
在这一行中,我们有一个简单的正则表达式匹配。 我们在`"Her name is Jane"`句子中寻找一个`"name"`字符串。 我们使用`=~`运算符。 该运算符还设置了三个特殊变量。 该行返回数字 4,这是比赛开始的位置。
W
wizardforcel 已提交
226

W
wizardforcel 已提交
227
```ruby
W
wizardforcel 已提交
228 229 230 231 232 233
p $`

```

`$``特殊变量包含最后一个匹配项之前的文本。

W
wizardforcel 已提交
234
```ruby
W
wizardforcel 已提交
235 236 237 238 239 240
p $&

```

`$&`具有匹配的文本。

W
wizardforcel 已提交
241
```ruby
W
wizardforcel 已提交
242 243 244 245 246 247
p $'

```

`$'`变量包含最后一个匹配项之后的文本。

W
wizardforcel 已提交
248
```ruby
W
wizardforcel 已提交
249 250 251 252 253 254 255 256 257 258 259 260 261 262
$ ./svars.rb
4
"Her "
"name"
" is Jane"

```

这是示例的输出。

## 锚点

锚点匹配给定文本内字符的位置。 我们介绍了三个锚定字符。 `^`字符与行的开头匹配。 `$`字符与行尾匹配。 `\b`字符与单词边界匹配。

W
wizardforcel 已提交
263
```ruby
W
wizardforcel 已提交
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
#!/usr/bin/ruby

sen1 = "Everywhere I look I see Jane"
sen2 = "Jane is the best thing that happened to me"

p sen1.match /^Jane/ 
p sen2.match /^Jane/ 

p sen1.match /Jane$/ 
p sen2.match /Jane$/ 

```

在第一个示例中,我们使用`^`和`$`锚定字符。

W
wizardforcel 已提交
279
```ruby
W
wizardforcel 已提交
280 281 282 283 284
sen1 = "Everywhere I look I see Jane"
sen2 = "Jane is the best thing that happened to me"

```

W
wizardforcel 已提交
285
我们有两个句子。 `"Jane"`一词位于第一个字母的开头和第二个字母的结尾。
W
wizardforcel 已提交
286

W
wizardforcel 已提交
287
```ruby
W
wizardforcel 已提交
288 289 290 291 292
p sen1.match /^Jane/ 
p sen2.match /^Jane/ 

```

W
wizardforcel 已提交
293
在这里,我们查看单词`"Jane"`是否位于两个句子的开头。
W
wizardforcel 已提交
294

W
wizardforcel 已提交
295
```ruby
W
wizardforcel 已提交
296 297 298 299 300 301 302
p sen1.match /Jane$/ 
p sen2.match /Jane$/ 

```

在这里,我们在句子的末尾查找文本的匹配项。

W
wizardforcel 已提交
303
```ruby
W
wizardforcel 已提交
304 305 306 307 308 309 310 311 312 313 314 315
$ ./anchors.rb
nil
#<MatchData "Jane">
#<MatchData "Jane">
nil

```

这些就是结果。

常见的要求是仅包含整个单词的匹配项。 默认情况下,我们会计算所有匹配项,包括匹配较大或复合词的匹配项。 让我们看一个例子来澄清问题。

W
wizardforcel 已提交
316
```ruby
W
wizardforcel 已提交
317 318 319 320 321 322 323 324 325 326 327 328 329
#!/usr/bin/ruby

text = "The cat also known as the domestic cat is a small, 
usually furry, domesticated, carnivorous mammal."

p text.scan /cat/

p $`
p $&
p $'

```

W
wizardforcel 已提交
330
我们有一句话。 在这句话中,我们寻找一只猫。 使用`scan`,我们查找句子中的所有`"cat"`字符串,而不仅仅是第一次出现。
W
wizardforcel 已提交
331

W
wizardforcel 已提交
332
```ruby
W
wizardforcel 已提交
333 334 335 336 337
text = "The cat also known as the domestic cat is a small, 
usually furry, domesticated, carnivorous mammal."

```

W
wizardforcel 已提交
338
问题在于文本内部有三个`"cat"`字符串。 除了匹配提到哺乳动物的`"cat"`以外,`/cat/`还匹配`"domesticated"`一词中的字母 8-10。 在这种情况下,这不是我们想要的。
W
wizardforcel 已提交
339

W
wizardforcel 已提交
340
```ruby
W
wizardforcel 已提交
341 342 343 344 345 346 347 348
$ ./boudaries.rb
["cat", "cat", "cat"]
"The cat also known as the domestic cat is a small, \nusually furry, domesti"
"cat"
"ed, carnivorous mammal."

```

W
wizardforcel 已提交
349
在下一个示例中,将使用`\b`定位符消除`"domesticated"`上的最后一次匹配。
W
wizardforcel 已提交
350 351 352

`\b`字符用于为我们要查找的单词设置边界。

W
wizardforcel 已提交
353
```ruby
W
wizardforcel 已提交
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
#!/usr/bin/ruby

text = "The cat also known as the domestic cat is a small, 
usually furry, domesticated, carnivorous mammal."

p text.scan /\bcat\b/

p $`
p $&
p $'

```

通过包含`\b`元字符来改进示例。

W
wizardforcel 已提交
369
```ruby
W
wizardforcel 已提交
370 371 372 373
p text.scan /\bcat\b/

```

W
wizardforcel 已提交
374
通过上面的正则表达式,我们将`"cat"`字符串作为整个单词来查找。 我们不计算子词。
W
wizardforcel 已提交
375

W
wizardforcel 已提交
376
```ruby
W
wizardforcel 已提交
377 378 379 380 381 382 383 384 385 386
$ ./boudaries2.rb
["cat", "cat"]
"The cat also known as the domestic "
"cat"
" is a small, \nusually furry, domesticated, carnivorous mammal."

```

这次有两场比赛。 并且特殊变量可以正确显示最后一次匹配之前和之后的文本。

W
wizardforcel 已提交
387
## 字符类
W
wizardforcel 已提交
388

W
wizardforcel 已提交
389
我们可以使用方括号将字符组合成字符类。 字符类与括号中指定的任何字符匹配。 `/[ab]/`模式表示`a`或`b`,而`/ab/`模式表示`a`后跟`b`。
W
wizardforcel 已提交
390

W
wizardforcel 已提交
391
```ruby
W
wizardforcel 已提交
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
#!/usr/bin/ruby

words = %w/ sit MIT fit fat lot pad /

pattern = /[fs]it/

words.each do |word|
   if word.match pattern
       puts "#{word} matches the pattern" 
   else
       puts "#{word} does not match the pattern" 
   end
end

```

我们有六个六个三个字母的单词组成的数组。 我们对具有特定字符集的数组字符串应用正则表达式。

W
wizardforcel 已提交
410
```ruby
W
wizardforcel 已提交
411 412 413 414
pattern = /[fs]it/

```

W
wizardforcel 已提交
415
这就是模式。 该模式在数组中查找`"fit"`和`"sit"`字符串。 我们使用字符集中的`"f"`或`"s"`。
W
wizardforcel 已提交
416

W
wizardforcel 已提交
417
```ruby
W
wizardforcel 已提交
418 419 420 421 422 423 424 425 426 427 428 429 430 431
$ ./classes.rb
sit matches the pattern
MIT does not match the pattern
fit matches the pattern
fat does not match the pattern
lot does not match the pattern
pad does not match the pattern

```

有两场比赛。

在下一个示例中,我们将进一步探索字符类。

W
wizardforcel 已提交
432
```ruby
W
wizardforcel 已提交
433 434 435 436 437 438 439 440 441 442
#!/usr/bin/ruby

p "car".match %r{[abc][a][rs]}
p "car".match /[a-r]+/
p "23af 433a 4ga".scan /\b[a-f0-9]+\b/

```

该示例包含三个带有字符类的正则表达式。

W
wizardforcel 已提交
443
```ruby
W
wizardforcel 已提交
444 445 446 447
p "car".match %r{[abc][a][rs]}

```

W
wizardforcel 已提交
448
此行中的正则表达式包含三个字符类。 每个都是一个字符。 `[abc]`是`a`,`b`或`c`。 `[a]`只是一个。 第三个`[rs]`是`r`或`s`。 与`"car"`字符串匹配。
W
wizardforcel 已提交
449

W
wizardforcel 已提交
450
```ruby
W
wizardforcel 已提交
451 452 453 454
p "car".match /[a-r]+/

```

W
wizardforcel 已提交
455
我们可以在字符类中使用连字符-字符。 连字符是表示以下字符的元字符:此处的`a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q`或`r`。 由于字符类仅适用于一个字符,因此我们也使用`+`重复字符。 这表示字符集中的前一个字符可以重复一次或多次。 `"car"`字符串满足这些条件。
W
wizardforcel 已提交
456

W
wizardforcel 已提交
457
```ruby
W
wizardforcel 已提交
458 459 460 461 462 463
p "23af 433a 4ga".scan /\b[a-f0-9]+\b/

```

在这一行中,我们有一个包含三个子字符串的字符串。 使用`scan`方法,我们检查十六进制数。 我们有两个范围。 第一个`[a-f]`代表从 a 到 f 的字符。 第二个字符`[0-9]`代表数字 0 到 9。`+`指定这些字符可以重复多次。 最后,`\b`元字符创建边界,该边界仅接受仅包含这些字符的字符串。

W
wizardforcel 已提交
464
```ruby
W
wizardforcel 已提交
465 466 467 468 469 470 471 472 473 474 475
$ ./classes2.rb
#<MatchData "car">
#<MatchData "car">
["23af", "433a"]

```

This is the example output.

如果字符类的第一个字符是插入号`^`,则该类被反转。 它匹配除指定字符以外的任何字符。

W
wizardforcel 已提交
476
```ruby
W
wizardforcel 已提交
477 478 479 480 481 482 483 484 485
#!/usr/bin/ruby

p "ABC".match /[^a-z]{3}/
p "abc".match /[^a-z]{3}/

```

在示例中,我们在字符类中使用插入符号。

W
wizardforcel 已提交
486
```ruby
W
wizardforcel 已提交
487 488 489 490
p "ABC".match /[^a-z]{3}/

```

W
wizardforcel 已提交
491
我们寻找一个包含 3 个字母的字符串。 这些字母可能不是`a`到`z`的字母。 因为所有三个字符均为大写字符,所以`"ABC"`字符串与正则表达式匹配。
W
wizardforcel 已提交
492

W
wizardforcel 已提交
493
```ruby
W
wizardforcel 已提交
494 495 496 497
p "abc".match /[^a-z]{3}/

```

W
wizardforcel 已提交
498
此`"abc"`字符串不匹配。 所有三个字符都在搜索范围之外。
W
wizardforcel 已提交
499

W
wizardforcel 已提交
500
```ruby
W
wizardforcel 已提交
501 502 503 504 505 506 507 508 509 510 511 512
$ ./caret.rb
#<MatchData "ABC">
nil

```

这里有示例输出。

## 量词

标记或组后的量词指定允许该前一个元素出现的频率。

W
wizardforcel 已提交
513
```ruby
W
wizardforcel 已提交
514 515 516 517 518 519 520 521 522 523 524 525
 ?     - 0 or 1 match
 *     - 0 or more
 +     - 1 or more
 {n}   - exactly n
 {n,}  - n or more
 {,n}  - n or less (??)
 {n,m} - range n to m

```

上面是常见量词的列表。

W
wizardforcel 已提交
526
```ruby
W
wizardforcel 已提交
527 528 529 530 531 532 533
#!/usr/bin/ruby

p "seven dig moon car lot fire".scan /\w{3}/
p "seven dig moon car lot fire".scan /\b\w{3}\b/

```

W
wizardforcel 已提交
534
在该示例中,我们要选择具有三个字符的单词。 `\w`字符是文字​​字符,`\w{3}`表示之前文字字符的三倍。
W
wizardforcel 已提交
535

W
wizardforcel 已提交
536
```ruby
W
wizardforcel 已提交
537 538 539 540 541 542
p "seven dig moon car lot fire".scan /\w{3}/

```

第一行只是从每个字符串中剪切前三个字符。 这不是我们想要的。

W
wizardforcel 已提交
543
```ruby
W
wizardforcel 已提交
544 545 546 547 548 549
p "seven dig moon car lot fire".scan /\b\w{3}\b/

```

这是一个改进的搜索。 我们将先前的模式放在`\b`边界元字符之间。 现在,搜索将仅找到具有三个字符的单词。

W
wizardforcel 已提交
550
```ruby
W
wizardforcel 已提交
551 552 553 554 555 556 557 558
$ ./nchars.rb
["sev", "dig", "moo", "car", "lot", "fir"]
["dig", "car", "lot"]

```

示例的输出。

W
wizardforcel 已提交
559
`{n,m}`是具有`n`到`m`个字符的字符串的重复结构。
W
wizardforcel 已提交
560

W
wizardforcel 已提交
561
```ruby
W
wizardforcel 已提交
562 563 564 565 566 567 568 569
#!/usr/bin/ruby

p "I dig moon lottery it fire".scan /\b\w{2,4}\b/

```

在上面的示例中,我们选择了具有两个,三个或四个字符的单词。 我们再次使用边界`\b`元字符来选择整个单词。

W
wizardforcel 已提交
570
```ruby
W
wizardforcel 已提交
571 572 573 574 575 576 577 578 579
$ ./rchars.rb
["dig", "moon", "it", "fire"]

```

该示例打印具有 2-4 个字符的单词数组。

在下一个示例中,我们将介绍`?`元字符。 后面跟有`?`的字符是可选的。 形式上,`?`前面的字符可以出现一次或 0 次。

W
wizardforcel 已提交
580
```ruby
W
wizardforcel 已提交
581 582 583 584 585 586 587 588 589
#!/usr/bin/ruby

p "color colour colors colours".scan /colou?rs/
p "color colour colors colours".scan /colou?rs?/

p "color colour colors colours".scan /\bcolor\b|\bcolors\b|\bcolour\b|\bcolours\b/

```

W
wizardforcel 已提交
590
假设我们有一个文本,我们要在其中查找颜色词。 这个词有两个不同的拼写,英语为`"colour"`和美国为`"color"`。 我们希望找到这两种情况,而且我们也希望找到它们的复数形式。
W
wizardforcel 已提交
591

W
wizardforcel 已提交
592
```ruby
W
wizardforcel 已提交
593 594 595 596
p "color colour colors colours".scan /colou?rs/

```

W
wizardforcel 已提交
597
颜色模式可以同时找到`"color"`和`"colour"`。 `?`元字符之前的`u`字符是可选的。
W
wizardforcel 已提交
598

W
wizardforcel 已提交
599
```ruby
W
wizardforcel 已提交
600 601 602 603
p "color colour colors colours".scan /colou?rs?/

```

W
wizardforcel 已提交
604
`colou?rs?`模式串使`u`和`s`字符成为可选字符。 因此,我们找到了所有四种颜色组合。
W
wizardforcel 已提交
605

W
wizardforcel 已提交
606
```ruby
W
wizardforcel 已提交
607 608 609 610 611 612
p "color colour colors colours".scan /\bcolor\b|\bcolors\b|\bcolour\b|\bcolours\b/

```

可以使用轮换来写相同的请求。

W
wizardforcel 已提交
613
```ruby
W
wizardforcel 已提交
614 615 616 617 618 619 620 621 622 623 624
$ ./qmark.rb
["colors", "colours"]
["color", "colour", "colors", "colours"]
["color", "colour", "colors", "colours"]

```

This is the example output.

在本节的最后一个示例中,我们将显示`+`元字符。 它允许将前面的字符重复 1 次或更多次。

W
wizardforcel 已提交
625
```ruby
W
wizardforcel 已提交
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
#!/usr/bin/ruby

nums = %w/ 234 1 23 53434 234532453464 23455636
    324f 34532452343452 343 2324 24221 34$34232/

nums.each do |num|
    m = num.match /[0-9]+/

    if m.to_s.eql? num
        puts num
    end              
end

```

在示例中,我们有一个数字数组。 数字可以包含一个或多个数字字符。

W
wizardforcel 已提交
643
```ruby
W
wizardforcel 已提交
644 645 646 647 648 649 650
nums = %w/ 234 1 23 53434 234532453464 23455636
    324f 34532452343452 343 2324 24221 34$34232/

```

这是一个字符串数组。 其中两个不是数字,因为它们包含非数字字符。 必须将它们排除在外。

W
wizardforcel 已提交
651
```ruby
W
wizardforcel 已提交
652 653 654 655 656 657 658 659 660 661
nums.each do |num|
    m = num.match /[0-9]+/

    if m.to_s.eql? num
        puts num
    end              
end

```

W
wizardforcel 已提交
662
我们遍历数组并将正则表达式应用于每个字符串。 表达式为`[0-9]+`,代表`0..9`中的任何字符,重复 0 次或多次。 默认情况下,正则表达式也会查找子字符串。 在`34$34232`中,引擎将 34 视为数字。 `\b`边界在这里不起作用,因为我们没有具体的字符并且引擎不知道在哪里停止寻找。 这就是为什么我们在块中包含`if`条件的原因。 仅当匹配项等于原始字符串时,该字符串才被视为数字。
W
wizardforcel 已提交
663

W
wizardforcel 已提交
664
```ruby
W
wizardforcel 已提交
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
$ ./numbers.rb
234
1
23
53434
234532453464
23455636
34532452343452
343
2324
24221

```

这些值是数字。

## 不区分大小写的搜索

W
wizardforcel 已提交
683
我们可以执行不区分大小写的搜索。 正则表达式后面可以有一个选项。 它是单个字符,以某种方式修改了模式串。 如果是不区分大小写的搜索,我们将应用`i`选项。
W
wizardforcel 已提交
684

W
wizardforcel 已提交
685
```ruby
W
wizardforcel 已提交
686 687 688 689 690 691 692 693 694 695 696 697 698 699
#!/usr/bin/ruby

p "Jane".match /Jane/
p "Jane".match /jane/
p "Jane".match /JANE/

p "Jane".match /jane/i
p "Jane".match /Jane/i
p "Jane".match /JANE/i

```

该示例显示了区分大小写和不区分大小写的搜索。

W
wizardforcel 已提交
700
```ruby
W
wizardforcel 已提交
701 702 703 704 705 706 707 708
p "Jane".match /Jane/
p "Jane".match /jane/
p "Jane".match /JANE/

```

在这三行中,字符必须与模式完全匹配。 只有第一行给出了匹配项。

W
wizardforcel 已提交
709
```ruby
W
wizardforcel 已提交
710 711 712 713 714 715
p "Jane".match /jane/i
p "Jane".match /Jane/i
p "Jane".match /JANE/i

```

W
wizardforcel 已提交
716
在这里,我们使用第二个`/`字符后面的`i`选项。 我们进行不区分大小写的搜索。 所有三行都匹配。
W
wizardforcel 已提交
717

W
wizardforcel 已提交
718
```ruby
W
wizardforcel 已提交
719 720 721 722 723 724 725 726 727 728 729 730
$ ./icase.rb
#<MatchData "Jane">
nil
nil
#<MatchData "Jane">
#<MatchData "Jane">
#<MatchData "Jane">

```

This is the output of the example.

W
wizardforcel 已提交
731
## 交替
W
wizardforcel 已提交
732 733 734

下一个示例说明了交替运算符`|`。 该运算符使您可以创建具有多种选择的正则表达式。

W
wizardforcel 已提交
735
```ruby
W
wizardforcel 已提交
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
#!/usr/bin/ruby

names = %w/Jane Thomas Robert Lucy Beky
    John Peter Andy/

pattern = /Jane|Beky|Robert/ 

names.each do |name|    

    if name =~ pattern
        puts "#{name} is my friend"
    else
        puts "#{name} is not my friend"
    end
end

```

名称数组中有 8 个名称。 我们将在该数组中寻找字符串的多个组合。

W
wizardforcel 已提交
756
```ruby
W
wizardforcel 已提交
757 758 759 760 761 762
pattern = /Jane|Beky|Robert/ 

```

这是搜索模式。 它说,简,贝基和罗伯特是我的朋友。 如果找到其中任何一个,就找到了我的朋友。

W
wizardforcel 已提交
763
```ruby
W
wizardforcel 已提交
764 765 766 767 768 769 770 771 772 773 774 775 776 777
$ ./alternation.rb
Jane is my friend
Thomas is not my friend
Robert is my friend
Lucy is not my friend
Beky is my friend
John is not my friend
Peter is not my friend
Andy is not my friend

```

在这里,我们看到了脚本的输出。

W
wizardforcel 已提交
778
## 子模式
W
wizardforcel 已提交
779

W
wizardforcel 已提交
780
我们可以使用括号`()`在样式内创建子模式。
W
wizardforcel 已提交
781

W
wizardforcel 已提交
782
```ruby
W
wizardforcel 已提交
783 784 785 786 787 788 789 790 791
#!/usr/bin/ruby

p "bookworm" =~ /book(worm)?$/
p "book" =~ /book(worm)?$/
p "worm" =~ /book(worm)?$/
p "bookstore" =~ /book(worm)?$/

```

W
wizardforcel 已提交
792
我们有以下正则表达式模式:`book(worm)?$`。 `(worm)`是子模式。 只有两个字符串可以匹配:`"book"`或`"bookworm"`。 `?`字符位于子模式之后,这意味着子模式在最终模式中可能会出现 0、1 次。 `$`字符在这里用于字符串的精确末尾匹配。 没有它,`bookstore`和`bookmania`这样的词也将匹配。
W
wizardforcel 已提交
793

W
wizardforcel 已提交
794
```ruby
W
wizardforcel 已提交
795 796 797 798 799 800 801 802 803
#!/usr/bin/ruby

p "book" =~ /book(shelf|worm)?$/
p "bookshelf" =~ /book(shelf|worm)?$/
p "bookworm" =~ /book(shelf|worm)?$/
p "bookstore" =~ /book(shelf|worm)?$/

```

W
wizardforcel 已提交
804
子模式经常与交替组合在一起以创建多个单词组合。 例如,`book(shelf|worm)`匹配`"bookshelf"`和`"bookworm"`,`book(shelf|worm)?`匹配`"bookshelf"`,`"bookworm"`和`"book"`。
W
wizardforcel 已提交
805

W
wizardforcel 已提交
806
```ruby
W
wizardforcel 已提交
807 808 809 810 811 812 813 814 815 816
$ ./subpatterns2.rb
0
0
0
nil

```

最后一个子模式不匹配。 请记住,0 并不意味着没有匹配。 对于`=~`运算符,它是匹配字符串的第一个字符的索引。

W
wizardforcel 已提交
817
## 电子邮件示例
W
wizardforcel 已提交
818 819 820

在最后一个示例中,我们创建一个用于检查电子邮件地址的正则表达式模式。

W
wizardforcel 已提交
821
```ruby
W
wizardforcel 已提交
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
#!/usr/bin/ruby

emails = %w/ luke@gmail.com andy@yahoo.com 23214sdj^as
    f3444@gmail.com /

pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,5}$/

emails.each do |email| 

    if email.match pattern
        puts "#{email} matches"
    else
        puts "#{email} does not match"
    end

end

```

请注意,此示例仅提供一种解决方案。 它不一定是最好的。

W
wizardforcel 已提交
843
```ruby
W
wizardforcel 已提交
844 845 846 847 848 849 850
emails = %w/ luke@gmail.com andy@yahoocom 23214sdj^as
    f3444@gmail.com /

```

这是一系列电子邮件。 其中只有两个有效。

W
wizardforcel 已提交
851
```ruby
W
wizardforcel 已提交
852 853 854 855 856 857 858 859
pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9-]+\.[a-zA-Z.]{2,5}$/

```

这就是模式。 这里的第一个`^`和最后一个`$`字符可得到精确的模式匹配。 模式前后不允许有字符。 电子邮件分为五个部分。

第一部分是本地部分。 这通常是公司,个人或昵称的名称。 `[a-zA-Z0-9._-]+`列出了我们可以在本地部分使用的所有可能字符。 它们可以使用一次或多次。 第二部分是文字`@`字符。 第三部分是领域部分。 通常是电子邮件提供商的域名:例如 yahoo 或 gmail。 字符集`[a-zA-Z0-9-]+`指定可以在域名中使用的所有字符。 `+`量词使

W
wizardforcel 已提交
860
使用一个或多个这些字符。 第四部分是点字符。 它前面带有转义字符`\`。 这是因为点字符是一个元字符,并且具有特殊含义。 通过转义,我们得到一个文字点。 最后一部分是顶级域。 模式如下:`[a-zA-Z.]{2,5}`顶级域可以包含 2 到 5 个字符,例如`sk, net, info, travel`。 还有一个点字符。 这是因为某些顶级域名(例如`co.uk`)有两个部分。
W
wizardforcel 已提交
861

W
wizardforcel 已提交
862
```ruby
W
wizardforcel 已提交
863 864 865 866 867 868 869 870 871 872 873
$ ./email.rb
luke@gmail.com matches
andy@yahoocom does not match
23214sdj^as does not match
f3444@gmail.com matches

```

正则表达式将两个字符串标记为有效的电子邮件地址。

在本章中,我们介绍了 Ruby 中的正则表达式。