转载请注明出处 来源:paraller's blog
原文排版连接: 点击跳转

想系统的学习正则表达式,在网上找了很多教程,其中《55分钟学会正则表达式》这个翻译自外网的教程讲的最系统详细,学完整个正则表达式的耗时大概在两个多小时的样子。
为什么写这篇文章,因为我觉得如果不是这篇文章太生硬,废话比较多,排版乱,有些地方存在错误的话,我觉得55分钟就学完了。所以重新整理排版了一次。

学习的工具是 cat log | grep -E 'pattern'

正则表达式的基础语法

核心知识点
  • 正则表达式由只代表自身的字面值和代表特定含义的元字符组成。
  • 字面值(Literals): 意味着它们查找的是自身
  • 元字符:代表一些模式匹配
句点 .
  • 一个.表示匹配任何单个字符。下面这个正则表达式c.t代表: 先找到c,接着找到任何单个字符,再找到t。
  • 将会找到cat,cot ,甚至字面值为c.t的字符串,但是不包括ct或者coot。
反斜杠 \
  • 任何元字符如果用一个反斜杆进行转义就会变成字面值。所以上述的正则表达式c\.t ,能够匹配文本 c.t
  • 文本a\h,可以通过 a\\h找到
字符类( Character classes )
  • 定义: 字符在方括号中的集合。表示:找到其中任意的字符
  • 正则表达式c[aeiou]t表示“找到c后跟一个元音字母,再找到t”。将会匹配到cat
  • 正则表达式[0123456789]表示找到一个数字
  • 正则表达式[a]a意义相同:“找到a”

一些转义的例子:

  • \[a\] 表示文本 [a]
  • [\[\]ab] 表示匹配一个 [ 或者 ] 或者 a 或者 b
  • [\\[\]] 表示“匹配一个\ 或者 [ 或者 ]

note:

  • 一些字符在字符类内部扮演着元字符的角色,但在字符类外部则充当字面值。比如:连字符 -
  • 一些字符做着相反的事。比如: .表示“匹配任意字符”,但是[.]表示“匹配句点”
  • 一些字符在两种情形都为元字符,但在各自情形里代表不同的含义。
字符类区间(ranges)

你可以在字符类中使用连字符来表示一个字母或数字的区间_:

  • [b-f][bcdef] 一个意思
  • [A-Z][ABCDEFGHIJKLMNOPQRSTUVWXYZ] 都表示“匹配大写字母”。
  • [1-9][123456789] 都表示“匹配一个非零数字”。

区间和单独的字符,可能会共存于同一个字符类:

  • [0-9.,]表示“匹配 一个数字 或者 一个. 或者 一个,”。
  • [0-9a-fA-F]表示“匹配一个十六进制数”。
  • [a-zA-Z0-9\-]表示“匹配 一个字母数字字符 或 -”。

Note:

  • 你可以尝试在区间内以非字母数字字符结束(比如abc[!-/]),但这在其它实现中的语法不一定对。即使语法正确,但在这个区间内很难看出包含了哪个字符。请不要这么干
  • 同样的,区间端点的范围应该一致。即使像[A-z]这种表达式在你选择的实现中合法,但它做的可能会与你想法用出入。
  • 注意。 区间是字符的区间,不是数字的区间。正则表达式[1-31]表示 找到一个1或一个 2或一个3,不是找到一个从1到31的整数
字符类的否定(negation)

你可以通过在最开始的位置使^来排除一个字符类。

  • [^a]表示“匹配除了a的任意字符”。
  • [^a-zA-Z0-9]表示“找到一个非字母数字字符”。
  • [\^abc]表示“找到一个^ 或者 a 或者 b 或者 c”。
  • [^\^]表示“找到除了^的任意字符”
字符类补充
  • \d 含义与[0-9]一致:“匹配一个数字”。
  • \w 的含义与[0-9A-Za-z_]一致:“匹配一个单词字符,( 字母或数字或下划线或汉字)”。
  • \s 表示“匹配任意空白字符(空格,tab)”。
  • \s+ 可以表示回车和换行
  • \D[^0-9]:“匹配任意非数字的字符”。
  • \W[^0-9A-Za-z_]:“匹配任意非单词字符(译者注:匹配任意不是字母,数字,下划线,汉字的字符)”。
  • \S 表示“匹配任意不是空白符的字符”。
  • \t 表示制表符
  • [\u4e00-\u9fa5] 表示中文和英文
  • [^\x00-\xff] 匹配双字节字符,中文也是双字节的字符,不包括英文
乘法器(Multipliers)

可以在字面值或者字符类后跟着一个大括号来使用乘法器。

  • 正则表达式a{1}同a,表示“匹配一个a”。
  • \d{3} 表示3个相连的数字。
  • a{0} 表示“匹配空字符”。
  • a\{2\} 代表文本 a{2}
  • 在字符类中大括号没有特别的含义。[{}]代表“匹配一个{ 或者 }
  • 乘法器没有记忆。[abc]{2}表示“匹配a或者b或者c,接着匹配a或者b或者c。这跟匹配aabbcc含义不同
乘法器区间
  • x{4,4} 跟x{4}一样。
  • colou{0,1}r 表示“匹配colour或color。
  • a{3,5} 表示“匹配aaaaa或aaaa或aaa”。
  • a{1,} 表示“在一列中找到一个或多个a”。然而你的乘法器将会是贪婪的。在找到第一个a后,它将会尽可能匹配到更多的a。
  • .{0,} 表示“匹配任何情形”。不管你的输入文本是什么——甚至为空

注意:

  • 优先选择更长的匹配,因为乘法器是贪婪的。如果你输入的文本是I had an aaaaawful day,该正则表达式就会在aaaaawful中匹配到aaaaa。不会在第三个a后就停止匹配。
  • 乘法器在找到第一个文本的时候就会停止,如果你的输入文本为I had an aaawful daaaaay,之后这个正则表达式会在第一次的匹配中于aaawful找到aaa。只有在你说“给我找到另一个匹配”的时候,它才会继续搜索然后在daaaaay中找到aaaaa
乘法器补充
  • ?代表的含义与{0,1}相同。比如说,colou?r表示“匹配colour或color”。
  • *等于{0,}。比如说,*表示“匹配一切”,跟上面提到的一样。
  • +等于{1,}。比如说,\w+表示至少匹配一个或以上的单词。 [0-9]+代表至少匹配一个或以上数字
  • \?\*\+表示?*+
  • [?*+]表示找到一个?或者一个*或者一个+
惰性(Non-greed)

前面说到乘法器是贪婪的,可以通过添加?来消除贪婪特性

  • \d{4,5}? 就会等于 \d{4} ,在找到合适的文本之后就停下来
  • ".*?"表示“匹配一个双引号,跟着一个尽可能少的字符,再跟着一个双引号”。这实际上很有用
分支(Alternation)

你可以使用管道符号来实现匹配多种选择:

  • cat|dog表示“匹配cat或dog”。
  • red|blue|red||blue以及|red|blue 都是同样的意思,“匹配red或blue或空字符串”。
  • a|b|c[abc]一样。
  • cat|dog|\|表示“匹配cat或dog或管道符号”。
  • [cat|dog]表示“找到a或c或d或d或g或o或t或一个管道符号”。
组合(Grouping)
  • 在一周中找到一天,使用(Mon|Tues|Wednes|Thurs|Fri|Satur|Sun)day
  • (\w*)ility等同于\w*ility。都表示“找到以ility结尾的单词”。为什么第一种形式更有用,后面会看到...
  • \(\)表示“匹配一个(后,再匹配一个)”。
  • [()]表示“匹配一个( 或 一个)”。
单词边界(Word boundaries)

单词边界是一个单词字符和非单词字符之间的位置。记住,一个单词字符是w,它是[0-9A-Za-z_],一个非单词字符是W,也就是1

文本的开头和结尾总是当作单词边界。输入的文本it's a cat有八个单词边界。如果我们在cat后追加一个空格,这里就会有九个单词边界。

  • 正则表达式\b表示“匹配一个单词边界”。
  • \b\w\w\w\b表示“匹配一个三个字母的单词”。
  • a\ba表示“找到a,跟着一个单词边界,接着找到a”。不管输入文本是什么,这个正则表达式永远都不会成功找到一个匹配。
  • 单词边界不是字符。它们宽度为零.下面的正则表达式表示相同的含义:
行边界(Line boundaries)

每一块文本会分解成一个或多个行,用换行符分隔,像这样:

  • 正则表达式^表示“匹配开始行”。
  • 正则表达式$表示“匹配结束行”。
  • ^$表示“匹配空行”。
  • ^.*$将会匹配整个文本,因为换行符是一个字符,所以.会匹配它。为了匹配单行,要使用惰性乘法器,^.?$ , ^.*?$
  • \^\$表示“匹配尖符号后跟着一个美元符号”。
  • [$]表示“匹配一个美元符”。然而,[^]是非法单正则表达式。要记住的是尖符号在方括号中时有不同的特殊含义。把尖符号放在字符类中,这么用[\^]
  • 像单词边界一样,行边界也不是字符。它们宽度为零。

捕获和替换

这里就是正则表达式开始变得异常强大的地方。

捕获组

你已经知道,括号是用来表示组。它们也可以用来捕获子串。如果正则表达式是一个很小的电脑程序,这个捕获组就是它的输出(的一部分)。

正则表达式(\w*)ility表示“找到一个以ility结束的单词”。捕获组1就是匹配了部分内容的\w*

  • 文本包含单词accessibility,捕获组1就是accessib
  • 文本只包含ility,捕获组1就是空字符串。

你可以拥有多个捕获组,它们甚至可以嵌套使用。捕获组从左到右进行编号。只要计算左圆括号。

假设我们到正则表达式是(\w+) had a ((\w+) \w+)。如果我们的输入文本是I had a nice day,那么:
捕获组1是I
捕获组2是nice day
捕获组3是nice

在一些实现中,你可能可以访问捕获组0,即完整匹配:I had a nice day

是的,这确实意味着圆括号有些重复。从一个成功返回的匹配中捕获组数量总是等于原来正则表达式中捕获组的数量。记住这一点,因为它可以帮助你理解一些令人困惑的情形。
正则表达式((cat)|dog)表示“匹配cat或dog”。这里总是存在两组捕获组。如果我们的输入文本是dog,那么捕获组1是dog,捕获组2是空字符串,因为另一个选择未被使用

正则表达式a(\w)*表示“ 匹配一个以a开头的单词”。这里总是只有一个捕获组(译者注:除去捕获组0):

  • 如果输入文本是a,捕获组1是空字符串。
  • 如果输入文本是ad,捕获组1是d
  • 如果输入文本是avocado,捕获组1是vocado
替换

一旦你用了正则表达式来查找字符串,你可以指定另一个字符串来替换它。第二个字符串时替换表达式

你可以在你的替换表达式中引用捕获组。这是你可以在替换表达式唯一能的特殊的事,它意味着你不必完全销毁你刚刚发现的东西。

比方说,你尝试去用ISO 8691格式的日期(YYYY-MM-DD)去替换美式日期(MM/DD/YY)。

  • 通过正则表达式(\d\d)/(\d\d)/(\d\d)开始。注意这里有三个捕获组:月,日和两个数字表示的年。
  • 通过使用一个\和一个捕获组号来引用一个捕获组。所以,你的替换表达式为20\3-\1-\2
  • 如果我们的输入文本是03/04/05(表示 3月4号,2005年),那么:

    • 捕获组1是03;
    • 捕获组2是04;
    • 捕获组3是05;
  • 你可以在替换表达式中多次引用捕获组。
  • 在替换表达式中的反斜杆必须进行转义。举个例子,你有一些在计算机程序的字面值中使用的文本。那就意味着你需要在普通文本中的每个双引号或者反斜杆前放置一个反斜杆。
  • 正则表达式([\"])中,捕获组1是"或者\
  • 替换表达式\\\1中,一个字面值反斜杆后跟着一个匹配的双引号或者反斜杆。
后向引用(Back-references)
  • 你可以在同样的表达式中引用同一个捕获组。这称为后向引用
  • 表达式([abc])\1表示匹配aabbcc
结合正则表达式编程

过度反斜线综合征(Excessive backslash syndrome)

在一些编程语言中,如Java,对于含有正则表达式的字符串没有提供特别的支持。字符串有自己的转义规则,这些规则与正则表达式的转义规则叠加,通常会导致反斜杆过多(overload)。比如(还是Java):

  • 为了匹配一个数字,正则表达式\d在源代码中变成String re = "\d;"
  • 为了匹配一个双引号字符串,"[^"]*"变成String re = "\"[^\"]*\"";。
  • 为了匹配一个反斜杆或者一个左方括号或者一个又方括号,正则表达式[\\\\[\\]]变成String re = "[\\\\\\[\\]]";。
  • String re = "\s";和String re = "[ ]";是一样的。注意不同的转义“优先级”。

在其它编程语言里,通过一个特殊标记来标识正则表达式,通常是正斜杆/。这里有一些JavaScript例子:

  • 为了匹配一个数字,\d变成var regExp = /\d/;。
  • 匹配一个反斜杆或者一个左方括号或者一个右方括号,var regExp = /[\\\\[\\]]/;。
  • var regExp = /\s/;和var regExp = /[ ]/;一样。
  • 当然,这意味着必须对正斜杠而不是双引号进行转义。匹配URL的前面部分:var regExp = /https?:\/\//;。

基于这一点,我希望你明白为什么我对你反复提及反斜杆。

练习

题目如下:

  • 将文本中的所有 中文 替换成 中文
  • 编写一个正则表达式匹配1到31(含)之间的整数。
  • 双引号内所有不包含 " 的文本
  • 双引号内所有文本

答案:

## Find:
(_)([^\x00-\xff]+)+(_)
## Replace
`\*\*\2\*\*`
[1-9]|[12][0-9]|3[01]
cat log | grep -E '"[^"]{0,}"'
cat log | grep -E '".{0,}"'

练习草稿

I had a nice daya,a
a!b
90
"i love you , mary!"
"i love you","hey"
food
z...z
a b     c
d       g
e
iec ieac
c[abc]at
2016-10-22 12:12:12
cat
c.t
c\.t  [a]

其他

偏移量(Offsets)

在文本编辑器中,会在你光标所在处开始搜索。这个编辑器会向前开始搜索文字,然后停在第一个匹配的地方。下一次搜索会在第一次完成搜索的地方的右侧开始。

当编程的时候,文本的_偏移量_必须的。这个偏移量会在代码中有明确的支持,或保存在包含文本的对象中(如Perl),或包含正则表达式的对象中(如JavaScirpt)。(在Java里,这是一个由正则表达式和复合对象的字符串。)在任何情况下,默认值> 0,表示文本的开始。搜索后,偏移量会自动更新,或者作为输出的一部分返回。

无论什么情况,通常很容易去使用循环来解决这个问题。

注意正则表达式匹配空字符串是完全可能的。 你可以立马实现的一个简单的例子是a{0}在这种情况下,新的偏移量等于旧偏移量,从而导致死循环。

一些实现可能保护你避免发生这些情况,但要查下对应的文档。

动态正则表达式

动态地构造一个正则表达式字符串时一定要小心。如果你使用的字符串不是固定的,那么它可能包含意想不到的元字符。这会导致语法错误。更糟糕的是,它可能产生一个语法正确,但行为不可预期的正则表达式。

有bug的Java代码:

String sep = System.getProperty("file.separator");
String[] directories = filePath.split(sep);

这个bug就是:String.split()认为sep是一个正则表达式。但是在Windows下,sep是由犯斜杆组成的字符串\.这不是一个语法正确的正则表达式。结果是:一个异常PatternSyntaxException。

任何一个优秀的编程语言都提供了一种机制,用以转义在一个字符串中出现的所有元字符。在Java中,你可以这么做:

String sep = System.getProperty("file.separator");
String[] directories = filePath.split(Pattern.quote(sep));
邮件地址

不要使用正则表达式来验证邮件地址。

首先,这很难保证正确无误。电子邮件地址确实符合一个正则表达式,但是这个表达式长又复杂地让人联想到世界末日。任何缩略都会可能产生遗漏(false negatives)。(你知道吗?电子邮件地址可以包含注释!)

其次,即使所提供的电子邮件地址符合正则表达式,但也并不能证明它的存在。验证电子邮件地址的唯一方法是发送电子邮件给它。

标记

在正式的应用中,不要使用正则表达式来解析HTML或XML。解析HTML/XML是

不可能使用简单的正则
一般来说很难
一个已解决了的问题。
不妨找一个已有的解析库来为你搞定这些工作。

一些场景

替换
Host    segmentfault.com
Connection  keep-alive
Content-Length  55
Accept  */*
Origin  https://segmentfault.com
X-Requested-With    XMLHttpRequest
User-Agent  Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
^(\S+)(\s+)(.{0,})
"\1":"\3",
"Host":"segmentfault.com",
"Connection":"keep-alive",
"Content-Length":"55",
"Accept":"*/*",
"Origin":"https://segmentfault.com",
"X-Requested-With":"XMLHttpRequest",
"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
文本块 换行匹配
---
layout:     post
tags:- linux
------(\n(.{0,}))*---

参考网站

55分钟学会正则表达式(译)


  1. 0-9A-Za-z_ ↩

正则表达式快速入门(归纳版)相关推荐

  1. 正则表达式快速入门,转载

    正则表达式快速入门 首先简单介绍下正则表达式: 在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要.正则表达式就是用于描述这些规则的工具.换句话说,正则表达式就是记录文本规则的 ...

  2. Opencv快速入门(C++版),新手向

    Opencv快速入门(C++版) 前言 1.图像的读取与显示 所使用的API接口: 代码演示: 2.图像色彩空间转换 所使用的API接口: 代码演示: 3.图像对象的创建与赋值 所使用的API接口: ...

  3. IDEA快速入门(Mac版)

    [持续更新]一篇今年年头的老文章顺道发布了,大家有任何问题可以留言沟通.当时刚刚加入团团,愿大家有机会还是购买一台MAC,确实能给大家的效率赋能,虽然在一开始会有一些艰难!⛽️ 望借着换工作的东风,好 ...

  4. Maven快速入门(IDEA版) - 尚硅谷

    尚硅谷的Maven课程,自己学习时记录的笔记 b站视频:Maven零基础入门教程 文章目录 一.概述 (一) 为什么需要Maven 1. 目前的技术 2. 开发中存在的问题 (二) 什么是Maven? ...

  5. 新手初学Regular Expression正则表达式--快速入门

    看一段英文视频,本来想着学些Natural Language Processing,看完发现原来这就是正则表达式呀,顿感简单呀.所以不要认为什么事情难,去做,去行动吧.不过,我知道对于正则表达式,我还 ...

  6. python快速入门期末版_史上最全Python快速入门教程,满满都是干货

    原博文 2020-10-11 17:07 − Python是面向对象,高级语言,解释,动态和多用途编程语言.Python易于学习,而且功能强大,功能多样的脚本语言使其对应用程序开发具有吸引力.Pyth ...

  7. python正则表达式快速入门_Python学习笔记——正则表达式入门

    标签: # 本文对正则知识不做详细解释,仅作入门级的正则知识目录. 正则表达式的强大早有耳闻,大一时参加一次选拔考试,题目就是用做个HTML解析器,正则的优势表现得淋漓尽致.题外话不多讲,直接上干货: ...

  8. 正则表达式快速入门(三)

    3. 用法举例说明 1) 表达式:\bhi\b 所需语法:\b--匹配一个单词的开始或结束,也就是指单词和空格间的位置: 含义说明:精确地查找"hi"这个单词 查找结果:能查找到类 ...

  9. 【Python】正则表达式快速入门(re模块的使用)【转载】

    原文链接:https://morvanzhou.github.io/tutorials/python-basic/basic/13-10-regular-expression/ 一.简单的匹配 正则表 ...

最新文章

  1. DNS服务在网络中的应用
  2. QOS是什么?(Quality of Service,服务质量)
  3. MM的静态寻址和动态寻址
  4. android 蒙版图片带拖动_Android实现蒙版弹出框效果
  5. mac系统快捷键大全详细介绍
  6. java使用impala存放多条sql_Impala基于内存的SQL引擎的详细介绍
  7. mysql计算同比和环比的区别_SQL 求同比 环比
  8. 软件工程实践 第四周第二次会议讨论
  9. html选项卡出现乱码,html乱码
  10. ES6——Promise笔记
  11. 深入了解 JavaScript 内存泄露
  12. linux 内核配置简介
  13. 怎样查询本机ip地址?如何利用花生壳获取外网IP教程
  14. python读写xls
  15. apt-get update出现无法连接上 archive.ubuntukylin.com:10006
  16. 英语日常短语积累(6)-银行考试真题
  17. 华为员工自杀事件有感
  18. android 阅读器自动滚动,Android编程实现小说阅读器滑动效果的方法
  19. 大学生如何让自己强大起来
  20. java毕业生设计新城街道社区的健康档案管理平台计算机源码+系统+mysql+调试部署+lw

热门文章

  1. 人类基因组最后一块拼图完成!Science罕见6篇连发
  2. Magic Leap 2实测出炉:视场角增大20度,重量减轻20%,透光率低至0.3%让AR特效更逼真...
  3. 3年完成2款云端AI芯片研发量产,百度造芯为什么这么快?
  4. 拒收苹果超10万元赏金!程序员小哥找出iCloud账户漏洞后,发文直指苹果不够公开透明...
  5. 杨元庆捐资1亿人民币,要为母校上海交大建“最好的”高性能计算中心
  6. 这个神经网络电饭煲卖2万,我的米不配下锅
  7. 中文分词最佳记录刷新了,两大模型分别解决中文分词及词性标注问题丨已开源...
  8. CPU也支持AI加速,英特尔发布第3代至强处理器,推理速度提升80%,阿里腾讯云都在用...
  9. 马斯克直聘AI人才:高中毕没毕业无所谓,但是编程能力得过硬
  10. 一个退休程序员,用高中几何方法,让百年数学难题逼近理论极限