正则表达式简介
正则表达式在从文本,代码,日志文件,电子表格甚至文档中提取信息时非常有用。尽管形式语言背后有很多理论,但以下教程将探索正则表达式的更实际用法,以便可以尽快使用它们。
使用正则表达式时要认识的第一件事是,所有内容本质上都是一个字符,我们正在编写模式以匹配特定的字符序列(也称为字符串)。大多数模式都使用普通的ASCII,包括键盘上的字母,数字,标点符号和其他符号,例如%#$ @ !,但是unicode字符也可以用于匹配任何类型的国际文本。
ABC
下面我们从ABC开始入门
练习一:匹配字符
匹配 abcdefg
匹配 abcde
匹配 abc
输入
abc
即可将上述都匹配成功
123
字符包括普通字母,但也包括数字。实际上,数字0-9也是字符。
可以使用字符\ d代替0到9之间的任何数字,用\D代替任何非数字字符。前面的斜杠将其与简单d字符区分开,并表示它是一个元字符。
练习二:匹配数字
匹配 abc123xyz
匹配 define "123"
匹配 var g = 123;
输入
123
即可匹配上述三条
圆点 .
用.(点)元字符,并且可以匹配任何单个字符(字母,数字,空格,所有内容)。你可能会注意到,这实际上会覆盖句点字符的匹配,因此,为了专门匹配句点,您需要使用斜杠\来使点转义。
练习三:与通配符匹配
匹配 cat.
匹配 896.
匹配 ?=+.
跳过 abc1
输入
...\.
即可完成前三项的匹配
匹配特定字符串
点元字符功能非常强大,但有时功能太强大。例如,如果我们匹配电话号码,则我们不想将字母“((abc)def-ghij)”验证为有效号码!
有一种使用正则表达式匹配特定字符的方法,方法是在方括号内定义它们。例如,模式[abc]仅匹配单个a,b或c字母,而没有其他匹配项。对应的,使用 方括号和^排除特定字符。例如,模式[^ abc]将匹配除字母a,b或c之外的任何单个字符。
练习四:匹配字符
匹配 can
匹配 man
匹配 fan
跳过 dan
跳过 ran
跳过 pan
输入
[cmf]am
或者[^drp]am
即可完成
字符范围
当使用方括号表示法时,可以使用 [ ]来指示字符范围,从而在顺序字符列表中匹配一个字符。例如,模式[0-6]将只匹配从零到六个的任何一位数字字符,而没有其他字符。同样,[^n-p]将仅匹配任何单个字符,但字母n至p内的除外。
同一括号内也可以使用多个字符范围,以及各个字符。一个示例是字母数字\w元字符,它等效于字符范围[A-Za-z0-9_],通常用于匹配英文文本中的字符。
练习五:匹配字符范围
匹配 Ana
匹配 Bob
匹配 Cpc
跳过 aax
跳过 bby
跳过 ccz
输入
[A-C][n-p][a-c]
即可匹配成功
匹配重复字符
一种更方便的方法是使用花括号表示法指定每个字符要重复多少次 。例如,一个{3}将与一个字符完全匹配三遍。某些正则表达式引擎甚至允许您指定此重复的范围,以使a {1,3}与字符匹配不超过3次,但不少于一次。
此量词可以与任何字符或特殊的元字符一起使用,例如w {3}(三个w),[wxy] {5}(五个字符,每个字符可以是w,x或y)和{2 ,6}(在任何字符的2到6之间)
练习六:匹配重复的字符
匹配 wazzzzzup
匹配 wazzzup
跳过 wazup
输入
waz{3,5}up
即可匹配成功
匹配任意数量的字符
有些字符串有0或多个或1或多个其跟随的字符(始终跟随一个字符或组),我们可以使用模式\ d *来匹配任意数量的数字,但是更严格的正则表达式将是\ d +,以确保输入字符串至少包含一位数字。
这些量词可以与任何字符或特殊元字符一起使用,例如a +(一个或多个a的字符),[abc] +(任何a,b或c字符中的一个或多个)和.*(任何字符的零个或多个))。
练习七:匹配重复的字符 plus
匹配 aaaabcc
匹配 aabbbbc
匹配 aacc
跳过 a
输入
aa+b*c+ 或者 a{2,4}b{0,4}c{1,2}
即可匹配
可选字符
匹配和提取文本时真正常见的另一个量词是?(问号)元字符,表示可选性。此元字符允许您匹配零或前面的字符或组之一。例如,模式ab?c将匹配字符串“ abc”或“ ac”,因为b被认为是可选的。
与点元字符类似,问号是一个特殊字符,您将不得不使用斜杠\?将其转义。匹配字符串中的普通问号字符。
练习八:匹配可选字符
匹配 1 file found?
匹配 2 files found?
匹配 24 files found?
跳过 No files found.
输入
\d+ files? found\?
即可匹配
所有的空格
在处理现实世界中的输入(例如日志文件甚至用户输入)时,很难不遇到空格。我们使用它来格式化信息片段,以使其更易于在视觉上阅读和扫描。
你会用正则表达式使用最常见的形式是空格(␣),缩进(\t),新行(\n)和回车(\r)(在Windows环境中很有用),而这些特殊字符与它们各自的空白匹配。另外,空格特殊字符\s将与上面的任何特定空格匹配,并且在处理原始输入文本时非常有用。
练习九:匹配空格
匹配 1. abc
匹配 2. abc
匹配 3. abc
跳过 4.abc
输入
\d\.\s+abc
即可完成匹配
开始和结束
加强模式的一种方法是使用特殊的^和$(美元符号)元字符定义一个描述行的开始和结束的模式。例如,我们可以使用模式^ success来仅匹配以单词“ success”开头的行,而不匹配“ Error:unsuccessful operation”行。而且,如果同时使用^ 和美元符号,则会创建一个与整个行的开头和结尾完全匹配的模式。
请注意,这与在一组括号[^ ...]内用于排除字符的帽子不同,在读取正则表达式时可能会造成混淆。
练习十:匹配行
匹配 Mission: successful
跳过 Last Mission: unsuccessful
跳过 Next Mission: successful upon capture of target
输入
^Mission: successful$
即可完全匹配
匹配组
正则表达式使我们不仅可以匹配文本,还可以提取信息以进行进一步处理。这是通过定义字符组并使用特殊的圆括号(和)元字符捕获它们来完成的。一对括号内的任何子模式将被 捕获为一个组。实际上,这可用于从各种数据中提取信息,例如电话号码或电子邮件。
例如,假设您有一个命令行工具来列出您在云中拥有的所有图像文件。然后,您可以使用诸如^(IMG \ d +\.png)$
之类的模式来捕获并提取完整文件名,但是如果您只想捕获不带扩展名的文件名,则可以使用模式^(IMG\d+\.png $
仅捕获句点之前的部分。
练习十一:匹配组
file_record_transcript.pdf 捕获file_record_transcript
file_07241999.pdf 捕获file_07241999
跳过 testfile_fake.pdf.tmp
输入
^(file.+)\.pdf$
即可捕获
嵌套组
使用复杂数据时,您很容易发现自己必须提取多层信息,这可能导致嵌套的组。通常,捕获组的结果按照定义它们的顺序(用空心括号括起来的顺序)。
以捕获列表中所有图像文件的文件名为例。如果每个这些图像文件的文件名中都有一个连续的图片编号,则可以通过编写类似^(IMG(\d+)\.png $
的表达式(使用嵌套)来使用相同的模式提取文件名和图片编号括号以捕获数字)。
嵌套组在模式中从左到右读取,第一个捕获组是第一个括号组的内容,依此类推。
练习十二:匹配嵌套组
Jan 1987 捕获 Jan 1987 1987
May 1969 捕获 May 1969 1969
Aug 2011 捕获 Aug 2011 2011
输入
(\w+ (\d+))
即可捕获
带条件的
精确总是好事,这适用于编码,对话甚至正则表达式。例如,您不会为某人写一份购物清单以购买更多, 因为您不知道可以得到什么。相反,您可以编写“购买更多的牛奶”或“ 购买更多的面包”,并且在正则表达式中,我们实际上可以定义这些条件。
特别是在使用组时,可以使用|(逻辑OR,也称为管道)来表示不同的可能字符集。在上面的示例中,我可以编写模式“购买更多(牛奶|面包|果汁)”以仅匹配字符串购买更多牛奶,购买更多面包或购买更多果汁。
练习十三:匹配条件文本
匹配 I love cats
匹配 I love dogs
跳过 I love logs
跳过 I love cogs
输入‘ I love (cats|dogs) ’即可匹配成功
实践问题(答案在文章末尾)
问题一:匹配十进制数字
匹配 3.14529
匹配 -255.34
匹配 128
匹配 1.9e10
匹配 123,340.00
跳过 720p
问题二:匹配电话号码
提取
捕获 415-555-1234 415
捕获 650-555-2345 650
捕获 (416)555-3456 416
捕获 202 555 4567 202
捕获 4035555678 403
捕获 1 416 555 9292 416
问题三:匹配电子邮件
提取
tom@hogwarts.com tom
tom.riddle@hogwarts.com tom.riddle
tom.riddle+regexone@hogwarts.com tom.riddle
tom@hogwarts.eu.com tom
potter@hogwarts.com potter
harry@hogwarts.com harry
hermione+regexone@hogwarts.com hermione
问题四:匹配HTML
提取
<a>This is a link</a> a
<a href='https://regexone.com'>Link</a> a
<div class='test_style'>Test</div> div
<div>Hello <span>world</span></div> div
问题五:匹配特定的文件名
提取
跳过 .bash_profile
跳过 workspace.doc
捕获 img0912.jpg img0912 jpg
捕获 updated_img0912.png updated_img0912 png
跳过 documentation.html
捕获 favicon.gif favicon gif
跳过 img0912.jpg.tmp
跳过 access.lock
问题六:从行首和行尾修剪空白
The quick brown fox... The quick brown fox...
jumps over the lazy dog. jumps over the lazy dog.
问题七:从日志文件中提取信息
提取
跳过 W/dalvikvm( 1553): threadid=1: uncaught exception
跳过 E/( 1553): FATAL EXCEPTION: main
跳过 E/( 1553): java.lang.StringIndexOutOfBoundsException
捕获 E/( 1553): at widget.List.makeView(ListView.java:1727) makeView ListView.java 1727
捕获 E/( 1553): at widget.List.fillDown(ListView.java:652) fillDown ListView.java 652
捕获 E/( 1553): at widget.List.fillFrom(ListView.java:709) fillFrom ListView.java 709
问题八:从URL解析和提取数据
提取
捕获 ftp://file_server.com:21/top_secret/life_changing_plans.pdf ftp file_server.com 21
捕获 https://regexone.com/lesson/introduction#section https regexone.com
捕获 file://localhost:4040/zip_file file localhost 4040
捕获 https://s3cur3-server.com:9999/ https s3cur3-server.com 9999
捕获 market://search/angry%20birds market search
提示1:
^-?\d+(,\d+)*(\.\d+(e\d+)?)?$
提示2:
(\d{3})
可捕获区号,要想捕获全部则1?[\s-]?\(?(\d{3})\)?[\s-]?\d{3}[\s-]?\d{4}
提示3:
^([\w\.]*)
提示4:
<(\w+)
当然>([\w\s]*)<
可以拿到标签内容,='([\w://.]*)'
可以拿到标签属性
提示5:
(\w+)\.(jpg|png|gif)$
提示6:
^\s*(.*)\s*$
提示7
(\w+)\(([\w\.]+):(\d+)\)
提示8:
(\w+)://([\w\-\.]+)(:(\d+))?