[关闭]
@Zjmainstay 2017-08-24T07:24:40.000000Z 字数 10035 阅读 1699

正则掌握程度测试题

正则表达式


注:解答时,点击“题样”链接,进行测试即可。
鼠标悬停到每段文字,右侧+可评论,大家可评论留下你的答案,我看到会适当加以回复,建议带上你们的Q群昵称(434252251 专精正则表达式)。

1. 分组提取/非捕获组

分组,是正则里一个非常重要的概念,我们需要针对某个区域提取数据,往往需要依赖分组。而分组,其实就是正则里()括住的部分。

(1.1)分组提取

  1. 需求:在分组1中匹配metaauthor属性的值
  2. 源串:
  3. <meta author="Zjmainstay" />
  4. another author="Zjmainstay too"
  5. 预期:分组1得到Zjmainstay
  6. 正则:

题样:http://regex.zjmainstay.cn/r/naCgc7/1

(1.2)非捕获组

针对上面的分组,有时候,我们并不需要捕获某个分组的内容,我们可以使用非捕获组(?:表达式),从而不捕获表达式部分内容到分组中。

  1. 需求:匹配每行字母个数是偶数个的数据,每行数据不为空,正则不能存在分组1
  2. 源串:
  3. a
  4. ab
  5. abc
  6. abcd
  7. 预期:
  8. 匹配得到 ab abcd,不包含分组1
  9. 正则:

题样:http://regex.zjmainstay.cn/r/bjLKbO/1

2. 单字符或

或条件是正则使用过程中常用的概念,比如,密码由字母或数字组成,这里就用到了或条件,而且,由于字母或数字都是单个字符,因此,可以使用[a-z0-9]这样的单字符或语法实现。
常犯错误:匹配a或b写成[a|b],此表达式实际上表示a或b或|,在[]内部的|表示其本身,注意区分(a|b)表示a或b的写法。

(2)单字符或

  1. 需求:匹配由 A/S/D/F 4个字母(区分大小写)组成的长度为3字符串
  2. 源串:
  3. ABC
  4. ASD
  5. ADS
  6. ASF
  7. BBC
  8. A|S
  9. A|D
  10. ASDF
  11. 预期:以[]元字符获得3个字母的或集,匹配 ASD/ADS/ASF 3组数据
  12. 正则:

题样:http://regex.zjmainstay.cn/r/kCK1ho/1

3. 多字符或

相对单字符或条件,多字符或也是很常见的,比如,我们需要匹配http或ftp两个协议头的url,就需要^(http|ftp)://.+$这样的语法来实现。

(3)多字符或

  1. 需求:匹配每行数据中以.jpg/.jpeg/.png/.gif结尾的图片名称(含后缀)
  2. 源串:
  3. image.jpg
  4. image.jpeg
  5. image.png
  6. image.gif
  7. not_image.txt
  8. not_image.doc
  9. not_image.xls
  10. not_image.ppt
  11. 预期:匹配 image.jpg/image.jpeg/image.png/image.gif 4个结果
  12. 正则:

题样:http://regex.zjmainstay.cn/r/OKW5IK/1

4. 分组引用

前面介绍了分组,那某个分组在我们匹配过程中重复出现,又该如何处理?分组引用恰恰解决这个问题。比如,匹配出现重复单词的一行数据,我们可以这么写(多行模式):/^.*?(\b\S+\b).*?\1.*$/m\1表示引用前面分组1中匹配到的内容,也就是重复的单词内容。

(4)匹配连续相同3次的数字

  1. 需求:匹配连续相同3次的数字
  2. 源串:
  3. 111
  4. 121
  5. 112
  6. 222
  7. 预期:匹配 111/222 两组数据
  8. 正则:

题样:http://regex.zjmainstay.cn/r/zvHpSG/1

5. 匹配换行数据

“我的正则本来好好的,突然不行了!”这个是很多正则新人遇到的问题,而这个问题,很多时候,就是因为原来正则中的.不能匹配新数据里的换行导致的。这时候,只需要把.改成[\s\S]这样的表达式就可以了。这个表达式表示空格或非空格,也就是任意字符啦。

(5)匹配换行数据

  1. 需求:分别使用单行模式和普通模式匹配id="author"div中数据,div标签不在同一行
  2. 源串:
  3. <div id="author">
  4. Zjmainstay
  5. </div>
  6. 预期:Zjmainstay
  7. 正则1
  8. 正则2

题样:http://regex.zjmainstay.cn/r/DiScsG/1

6. 存在(或)

(6.1)匹配多种或条件的数据,没有特殊限制

  1. 需求:匹配每行中包含“作者”或者“读者”的数据
  2. 源串:
  3. 本文的作者是Zjmainstay
  4. 本文有很多读者
  5. 读者可以是任何一个地方的人
  6. 这里的任何一个地方说明读者也能在国外
  7. 什么乱七八糟的推理
  8. 你不匹配我,凭什么要我推荐你的博客 www.zjmainstay.cn
  9. 预期:匹配
  10. 本文的作者是Zjmainstay
  11. 本文有很多读者
  12. 读者可以是任何一个地方的人
  13. 这里的任何一个地方说明读者也能在国外
  14. 正则:

题样:http://regex.zjmainstay.cn/r/uNX6mw/1

(6.2)匹配多种或条件的数据,有特殊限制(不使用环视)

  1. 需求:匹配每行中“读者”在开头或结尾的数据
  2. 源串:
  3. 本文作者是Zjmainstay,有很多读者
  4. 读者可以是任何一个地方的人
  5. 这里的任何一个地方说明读者也能在国外
  6. 预期:匹配
  7. 本文作者是Zjmainstay,有很多读者
  8. 读者可以是任何一个地方的人
  9. 正则:

题样:http://regex.zjmainstay.cn/r/xc3L4j/1

(6.3)匹配多种或条件的数据,有特殊限制(使用环视)

  1. 需求:匹配每行中“读者”在开头或结尾的数据
  2. 源串:
  3. 本文作者是Zjmainstay,有很多读者
  4. 读者可以是任何一个地方的人
  5. 这里的任何一个地方说明读者也能在国外
  6. 预期:匹配
  7. 本文作者是Zjmainstay,有很多读者
  8. 读者可以是任何一个地方的人
  9. 正则:

题样:http://regex.zjmainstay.cn/r/xqmjdg/1

7. 存在(与)

(7.1)校验密码必须包含字母、数字和特殊字符,6-16位

  1. 需求:校验密码必须包含字母、数字和特殊字符,6-16位,假定特殊字符为 -_= 三个字符
  2. 源串:
  3. 12345
  4. 123456
  5. 1234561234561234
  6. 12345612345612345
  7. a1234
  8. a12345
  9. -1234
  10. -12345
  11. a-123
  12. a-1234
  13. a-1234a-1234a-12
  14. a-1234a-1234a-1234
  15. aaaaa
  16. aaaaaa
  17. -_=-_
  18. -_=-_=
  19. 预期:匹配
  20. a-1234
  21. a-1234a-1234a-12
  22. 正则:

题样:http://regex.zjmainstay.cn/r/x8Hk1c/1

8. 特殊限制(环视否定)

(8.1)使用\d{1,3}匹配1-999的数据,不能以0开头

  1. 需求:使用\d{1,3}匹配每行中1-999的数据,不能以0开头
  2. 源串:
  3. 1
  4. 10
  5. 100
  6. 999
  7. 1000
  8. 01
  9. 001
  10. 预期:匹配
  11. 1
  12. 10
  13. 100
  14. 999
  15. 正则:

题样:http://regex.zjmainstay.cn/r/cOuCVG/1

(8.2)匹配除了span标签外的所有标签

  1. 需求:匹配除了<span>内容</span>标签外的所有<tagName>内容</tagName>格式标签
  2. 源串:
  3. <div>匹配我</div>
  4. <span>不匹配我</span>
  5. <p>匹配我</p>
  6. <i>匹配我</i>
  7. 预期:匹配
  8. <div>匹配我</div>
  9. <p>匹配我</p>
  10. <i>匹配我</i>
  11. 正则:

题样:http://regex.zjmainstay.cn/r/o70yEp/1

9. 替换分组使用

(9.1)给源串每个链接加上http://www.zjmainstay.cn前缀

  1. 需求:给源串每个链接加上http://www.zjmainstay.cn前缀
  2. 源串:
  3. <a id="link-1" href="/regexp-one">正则文章合集(All In One)</a>
  4. <a id="link-2" href="/my-regexp">正则入门教程</a>
  5. <a id="link-3" href="/deep-regexp">正则高级教程</a>
  6. <a id="link-4" href="/regexp-lookaround">正则环视详解</a>
  7. <a id="link-5" href="/php-curl">PHP cURL应用</a>
  8. 预期:替换得到
  9. <a id="link-1" href="http://www.zjmainstay.cn/regexp-one">正则文章合集(All In One)</a>
  10. <a id="link-2" href="http://www.zjmainstay.cn/my-regexp">正则入门教程</a>
  11. <a id="link-3" href="http://www.zjmainstay.cn/deep-regexp">正则高级教程</a>
  12. <a id="link-4" href="http://www.zjmainstay.cn/regexp-lookaround">正则环视详解</a>
  13. <a id="link-5" href="http://www.zjmainstay.cn/php-curl">PHP cURL应用</a>
  14. 查找:
  15. 替换:

题样:http://regex.zjmainstay.cn/r/7UyRrm/1

(9.2)将每行数据格式化为一条SQL语句

  1. 需求:将每行特定格式数据格式化为SQL语句
  2. 源串:
  3. 1 2017-04-11 Zjmainstay
  4. 2 2017-04-12 Nobody
  5. 3 2017-04-13 Somebody
  6. 预期:替换得到
  7. INSERT INTO table_log(`id`, `created_at`, `author`) values('1', '2017-04-11', 'Zjmainstay');
  8. INSERT INTO table_log(`id`, `created_at`, `author`) values('2', '2017-04-12', 'Nobody');
  9. INSERT INTO table_log(`id`, `created_at`, `author`) values('3', '2017-04-13', 'Somebody');
  10. 查找:
  11. 替换:

题样:http://regex.zjmainstay.cn/r/lUKwVK/1

10. 分组可选

(10.1)分组可选

  1. 需求:判断如果单词以A开头,匹配Apple;如果单词以B开头,匹配Banana;否则匹配Empty
  2. 源串:
  3. Angle
  4. Apple
  5. Banana
  6. Best
  7. Empty
  8. 预期:匹配
  9. Apple
  10. Banana
  11. Empty
  12. 正则:

题样:http://regex.zjmainstay.cn/r/6tlUkg/1

(10.2)分组可选与分组引用

  1. 需求:匹配html标签的属性值,属性值可以由双引号、单引号、无单双引号定界
  2. 源串:
  3. <div id="I'm Zjmainstay" class="name" data-year=2017 age='27'>
  4. 预期:分组匹配
  5. I'm Zjmainstay
  6. author
  7. 2017
  8. 27
  9. 正则:

题样:http://regex.zjmainstay.cn/r/KGtpyr/1

11. 单字符拆分(数字)

(11)匹配0.00-100.00的数值,可以有0-2位小数

  1. 需求:匹配0.00-100.00的数值,可以有0-2位小数,不能以小数点结尾,不能以2个以上的0开头
  2. 思路:(100|10-99|0-9) + 0-2小数位 + 排除小数点结尾、2个以上0开头的情况
  3. 源串:
  4. 0
  5. 1
  6. 0.0
  7. 0.00
  8. 9.00
  9. 18.00
  10. 27.0
  11. 36.00
  12. 45.00
  13. 54.00
  14. 63.00
  15. 72.00
  16. 81.00
  17. 90.00
  18. 99.99
  19. 100.00
  20. 0.
  21. 001
  22. 100.01
  23. 100.001
  24. 101
  25. 预期:匹配0.00~100.00
  26. 正则:

题样:http://regex.zjmainstay.cn/r/k1xZ7n/1

12. 贪婪模式

贪婪模式,正则会优先尽可能多地匹配能匹配到的内容。当剩余正则匹配剩余部分字符(源串)但无法满足匹配时,贪婪部分回溯,吐出已匹配的内容,尝试满足剩余部分字符的匹配。

(12.1)匹配链接中的文件名

  1. 需求:利用贪婪模式,分组1得到每行链接中的文件名
  2. 源串:
  3. http://localhost.com/a/b/c/d/file1.txt
  4. https://localhost.com/a/b/file2long.jpg
  5. 预期:分组0匹配行数据,分组1匹配文件名
  6. file1.txt
  7. file2long.jpg
  8. 正则:

题样:http://regex.zjmainstay.cn/r/nOkbk0/1

(12.2)限定字符贪婪优化匹配性能

  1. 需求:匹配div id="author"的标签内容
  2. 源串:
  3. <div id="author" class="author-text something-useless">Zjmainstay</div>
  4. 预期:利用贪婪模式去掉div中的噪点(无关数据),分组1匹配到Zjmainstay
  5. 正则:

题样:http://regex.zjmainstay.cn/r/Z02iP8/1

13. 非贪婪模式

贪婪模式,正则会优先尽可能少地匹配能匹配到的内容。当剩余正则匹配剩余部分字符(源串)但无法满足匹配时,非贪婪部分继续匹配更多内容,尝试满足剩余部分字符的匹配。

(13)匹配p标签内容

  1. 需求:匹配p标签内容
  2. 源串:
  3. <p>内容1</p><p>内容2</p>
  4. 预期:
  5. 在分组1中匹配到内容1和内容2
  6. 正则:

题样:http://regex.zjmainstay.cn/r/51oUUL/1

14. 占用模式(PCRE)

贪婪模式后再加一个+量词,如.++,效果是贪婪而且不回溯。
暂时没有想到应用场景。

15. |字符分界(|的作用域)

|作为或条件分隔符,它的分隔区间常常存在误用。在使用|字符的过程中,我们常常需要结合()来对它进行限定。如,^([0-9]+|[a-z]+)$表示纯数字或纯字母,如果没有(),那它又是另一种意思了。^[0-9]+|[a-z]+$等价于^[0-9]+[a-z]+$,因此,它表示数字开头或者字母结尾,跟我们的需求有了很大的差别。

(15)|字符分界

  1. 需求:在分组1中匹配cssscript的链接
  2. 源串:
  3. <script src="main.min.js" type="text/javascript"></script>
  4. <link rel="stylesheet" type="text/css" href="main.css">
  5. 预期:
  6. main.min.js
  7. main.css
  8. 正则:

题样:http://regex.zjmainstay.cn/r/P1Y39F/1

16. 元字符转义

元字符,指正则中有特殊意义的字符,如.表示匹配除了换行符以外的任意字符,这个.就是元字符。在正则书写过程中,如果我们真的要匹配这个.,就需要对它进行转义,而不是让它使用正则的含义,比如,匹配域名里的.,我们就要写成/zjmainstay\.cn/这样的正则。

(16)元字符转义

  1. 需求:表达式格式固定,提取其中的数值
  2. 源串:
  3. (20+170)-5*1/5=?
  4. 预期:
  5. A:20
  6. B:170
  7. C:5
  8. D:1
  9. E:5
  10. F:?
  11. 正则:
  12. 替换:

题样:http://regex.zjmainstay.cn/r/8y9RbP/1

17. 分隔符绕过(PCRE)

有时候,如果该语言支持多种分隔符,在写正则的过程中通常会通过规避分隔符的方式,减少对分隔符的转义,让正则看起来更清晰,写起来更舒服,当然,js中是不支持的。

(17)分隔符绕过

  1. 需求:在不对/转义的情况下匹配p标签内容
  2. 源串:
  3. <p>内容1</p><p>内容2</p>
  4. 预期:
  5. 在分组1中匹配到内容1和内容2
  6. 正则:

题样:http://regex.zjmainstay.cn/r/9dm3Wu/1

18. 匹配溢出排除

匹配溢出,这不是一个术语名词,是我自己的叫法,主要指正则匹配内容超出了我们预期,导致匹配得到非预期的结果。

(18.1)div标签匹配溢出

  1. 需求:匹配内容为数字的div
  2. 源串:
  3. <div class="aaa bbb">ABC</div><div class="bbb ccc">123</div>
  4. 预期:
  5. <div>123</div>
  6. 错误正则:/<div.*?>\d+<\/div>/
  7. 正则:

题样:http://regex.zjmainstay.cn/r/NYVDnY/1

(18.2)多字符排除

  1. 需求:匹配不包含某个单词或词语的内容
  2. 源串:
  3. http://www.zjmainstay.cn
  4. http://www.baidu.com
  5. http://www.qq.com
  6. 预期:
  7. http://www.zjmainstay.cn
  8. http://www.qq.com
  9. 正则:

题样:http://regex.zjmainstay.cn/r/Lo1KOf/1

(18.2)多字符排除

  1. 需求:匹配不包含某个单词或词语的内容
  2. 源串:
  3. A("Excalibur", "誓约胜利之剑", LONG_SWORD, (SPFX_NOGEN | SPFX_RESTR | SPFX_SEEK | SPFX_DEFN | SPFX_INTEL | SPFX_SEARCH),
  4. 0, 0, PHYS(5, 10), DRLI(0, 0), NO_CARY, 0, A_LAWFUL, PM_KNIGHT, NON_PM, 4000L, NO_COLOR);
  5. /*
  6. * Stormbringer only has a 2 because it can drain a level,
  7. * providing 8 more.
  8. */
  9. A("Stormbringer", "兴风者", RUNESWORD,
  10. (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN | SPFX_INTEL | SPFX_DRLI), 0, 0,
  11. DRLI(5, 2), DRLI(0, 0), NO_CARY, 0, A_CHAOTIC, NON_PM, NON_PM, 8000L,
  12. NO_COLOR);
  13. /*
  14. * Mjollnir will return to the hand of the wielder when thrown
  15. * if the wielder is a Valkyrie wearing Gauntlets of Power.
  16. */
  17. A("Mjollnir", "雷神之锤", WAR_HAMMER, /* Mjo:llnir */
  18. (SPFX_RESTR | SPFX_ATTK), 0, 0, ELEC(5, 24), NO_DFNS, NO_CARY, 0,
  19. A_NEUTRAL, PM_VALKYRIE, NON_PM, 4000L, NO_COLOR);
  20. A("Cleaver", "撕裂者", BATTLE_AXE, SPFX_RESTR, 0, 0, PHYS(3, 6), NO_DFNS, NO_CARY, 0, A_NEUTRAL, PM_BARBARIAN, NON_PM, 1500L, NO_COLOR);
  21. /*
  22. * Grimtooth glows in warning when elves are present, but its
  23. * damage bonus applies to all targets rather than just elves
  24. * (handled as special case in spec_dbon()).
  25. */
  26. A("Grimtooth", "邪兽之牙", ORCISH_DAGGER, (SPFX_RESTR | SPFX_WARN | SPFX_DFLAG2),
  27. 0, M2_ELF, PHYS(2, 6), NO_DFNS,
  28. NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ORC, 300L, CLR_RED);
  29. /*
  30. * Orcrist and Sting have same alignment as elves.
  31. *
  32. * The combination of SPFX_WARN+SPFX_DFLAG2+M2_value will trigger
  33. * EWarn_of_mon for all monsters that have the M2_value flag.
  34. * Sting and Orcrist will warn of M2_ORC monsters.
  35. */
  36. A("Orcrist", "杀兽剑", ELVEN_BROADSWORD, (SPFX_WARN | SPFX_DFLAG2), 0, M2_ORC, PHYS(5, 0),
  37. NO_DFNS, NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ELF, 2000L, CLR_BRIGHT_BLUE); /* bright blue is actually light blue */
  38. 预期:
  39. Excalibur=誓约胜利之剑
  40. Stormbringer=兴风者
  41. Mjollnir=雷神之锤
  42. Cleaver=撕裂者
  43. Grimtooth=邪兽之牙
  44. Orcrist=杀兽剑
  45. 查找:
  46. 替换:

题样:http://regex.zjmainstay.cn/r/CtesYn/1

19. 环视循环提取格式化

在数据处理过程中,经常遇到一些格式化处理,比如简单地将一批数据格式化为SQL(参考9.2),还有复杂的需要对一行数据的某部分进行循环提取,然后格式化为特定格式。

  1. 需求:循环提取每行数据的分支部分和固定部分,格式化为特定格式
  2. 源串:
  3. BBB|CCC|DDD=AAA
  4. FFF|GGG|HHH|III|JJJ|KKK=EEE
  5. 预期:
  6. BBB=AAA
  7. CCC=AAA
  8. DDD=AAA
  9. FFF=EEE
  10. GGG=EEE
  11. HHH=EEE
  12. III=EEE
  13. JJJ=EEE
  14. KKK=EEE
  15. 查找:
  16. 替换:

题样:http://regex.zjmainstay.cn/r/jpgKRF/1

20. 三段论应用

三段论,是本人根据对正则的理解,归纳出来的三句话:定锚点,去噪点,取数据
锚点,在正则中指^$\b这类零宽的位置,这里做了衍生,指能够唯一确定我们目标数据位置的参照点,比如author=Zjmainstay,我们要匹配author属性的数据,则author=就是我们的参照点,通过它,我们能快速写出提取author属性的数据的正则:author=(.+)
噪点,就是对我们提取数据产生干扰的无关数据,我们在做正则匹配提取数据的过程中,可以选择性的忽略它们。当然,这里的忽略不是指不需要对它们做匹配,而是不需要对它们做精确匹配。比如,<a class="some-class-1 some-class-xxx" style="border:1px solid" href="http://www.zjmainstay.cn/regexp" title="正则表达式教程">正则表达式</a>,我们要提取a标签的url和文本(正则表达式),这时候,a标签上的classstyletitle这些属性,对我们来说就没有意义了,它们就是噪点,在匹配过程中我们可以选择性的忽略它们(使用通配符进行匹配消耗掉它们),因此得到正则:<a [^>]*?href="([^"]+)"[^>]*>(.*?)</a>
数据,这个当然是指我们需要提取的内容了,如上面锚点举例,我们通过author=(.+)(.+)Zjmainstay部分数据进行了提取,因此,匹配结果的分组1(程序语言中的数组下标1)中,就能得到我们的结果。而对于多个数据的提取,如噪点举例,我们只需要针对数据部分进行多个分组(括号)的提取即可。
分组的计数,一般可以数左括号,排除环视和非捕获组的左括号,从1开始,依次加1递增,1,2,3,4....n,不同语言最大分组个数不同,大家在使用过程中自行留意,不过一般用不了那么多分组。
理解了三段论的概念,我们在写正则的过程中,只需要将源串进行分割划分,根据目标数据确定锚点,过滤噪点,提取数据,就能得到我们想要的正则了。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注