正则表达式学习
正则表达式:是处理字符串的⼀种表达⽅式。提供了⼀种从⼀组字符串中
选择特定字符串的机制
POSIX
规范定义了UNIX
操作系统应当⽀持的功能,POSIX
规范的正则表达式:
BRE
:(Basic Regular Expression
)基本型正则表达式ERE
:(Extended Regular Express
)扩展型正则表达式
BRE
和ERE
⼆者的区别,简单的说就在于(
、)
、{
、}
、+
、?
、|
这7
个特殊字符的使⽤⽅法上:
- 在
BRE
中,如果想要这些字符表示特殊的含义,就需要把它们转义。元字符(
、)
、{
、}
、+
、?
、|
必须转义之后才具有特殊含义,如\+
、\?
、\|
,⽽且也⽀持\1
、\2
之类反向引⽤- 反之,在
ERE
中,如果要这些字符不表示特殊的含义,就需要把它们转义。虽然BRE
名为“基本”⽽ERE
名为“扩展”,但ERE
并不要求兼容BRE
的语法,⽽是⾃成⼀体BRE
中的特殊字符:.
、\
、[
、^
、$
、*
ERE
中的特殊字符多了7
个,即:.
、\
、[
、^
、$
、*
、(
、)
、{
、}
、+
、?
、|
正则表达式与通配符没有任何关系,不是包含关系
- 通配符,是
Shell
提供的功能- 正则表达式只是⽤来处理字符串
如何学习正则表达式?
- 背,一些特殊字符的意义
- 实际练习
案例:
⼀个常⻅的正则表达式
^1[3-9](\d{9})$
^
:锚点操作符,匹配字符串的开头[3-9]
:列表操作符,只匹配中括号中的⼀个字符。-
:范围操作符指定范围\d
:代表0-9
数字{9}
:间隔运算符,匹配前⼀个元素⼏次(\d{9})
:分组/捕获组,定义⼀个⼦表达式$
:锚点操作符,匹配字符串的结尾
特殊符号的意义
直抒胸臆操作符:
类别 匹配类型 匹配字符 Cat
字符串 Cat
,属于串联Cat
,不能匹配Catt
C
字符 C
C
渣男操作符:
类别 匹配类型 匹配字符 .
匹配所有的字符,除了 newline
和null
通吃 lsp
重复操作符:
类别 匹配类型 *
匹配前⼀个元素 0
次或多次+
匹配前⼀个元素 1
次或多次?
匹配前⼀个元素 0
次或1
次
间隔操作符 { ... }:
类别 匹配类型 {count}
匹配前⼀个元素 count
次{min,}
匹配前⼀个元素⾄少 min
次{min, max}
匹配前⼀个元素⾄少 min
次,⾄多max
次
备胎操作符:
类别 匹配类型 匹配字符 |
匹配前⼀个表达式或后⼀个表达式 在吗?我怀孕了
列表操作符 [ ... ] and [^ ... ] :
⼀般操作符在列表操作符⾥会失去特殊意义,除了:
类别 匹配类型 ]
结束列表, []]
\
转义字符 [:
字符类别操作符开始 :]
字符类别操作符结束 -
范围操作符, 0-9
字符类别操作符 [: ... :] :
类别 匹配类型 匹配字符 [:alnum:]
[A-Za-z0-9]
数字和字⺟字符 [:alpha:]
[A-Za-z]
字⺟字符 [:blank:]
[ \t]
空格和 TAB
[:cntrl:]
[\x00-\x1F\x7F]
控制符 [:digit:]
[0-9]
数字 [:graph:]
[\x21-\x7E]
可视字符 [:lower:]
[a-z]
⼩写字⺟字符 [:print:]
[\x20-\x7E]
可视字符和空格( ASCII
,040-0176
)[:punct:]
][!"#$%&'()*+,./:;<=>?@\^_`{|}~-]
标点符号 [:space:]
[\t\r\n\v\f]
空⽩字符 [:upper:]
[A-Z]
⼤写字⺟字符 [:xdigit:]
[A-Fa-f0-9]
⼗六进制字符
特殊字符类别操作符:
类别 匹配类型 匹配字符 \w
[:alnum:]
数字和字⺟字符 \d
[:digit:]
数字 \W
[^[:alnum:]]
除了数字和字⺟字符 \B
[^[:digit:]]
除了数字 \<
^
匹配字符串的开头 \>
$
匹配字符串的结尾 \b
to\b
匹配to!
,但不匹配tomorrow
匹配单词边界字符
范围操作符:
类别 匹配类型 -
匹配指定范围,但是需在列表中使⽤,并指定范围,如 [a-z]
。[-az]
或者[az-]
表示匹配字⺟a
和z
还有-
锚点操作符:
类别 匹配类型 ^
匹配字符串的开头,需在开头 $
匹配字符串的结尾或者换⾏符的前⼀个位置,需在结尾
- 如果
^
在列表操作符中使⽤,并且在⾸位,代表取反
操作符优先级:
优先级(由⾼到低) 操作符 归类相关的括号符号 [::]
转义字符 \<特殊字符>
括号表达 []
分组 ()
单字符重复 * + ?{m, n}
串联 .
锚点 ^ $
备选 |
基础示例
grep
-v
:逆转显示-i
:忽略⼤⼩写-A
:向上显示⼏⾏-B
:向下显示⼏⾏-E
:启⽤扩展—color
:显示颜⾊
egrep
- 使用
grep -E
,启用ERE
扩展型正则表达式
案例:
打开
test.swift
文件,写入以下文本:struct LGTeacher { let name: String let class: String let credit:String let description: String } struct LGTeachers { let name: String let class: String let credit:String let description: String } extension LGTeacher { static var all: [LGTeacher] { [ LGTeacher( name: "Cooci", license: "http://creativecommons.org/licenses/by-sa/3.0", credit: "http://commons.wikimedia.org/wiki/User:Lin%C3%A91", description: "Basil is commonly used fresh in cooked recipes. In general, it is added at the last moment, as cooking quickly destroys the flavor. The fresh herb can be kept for a short time in plastic bags in the refrigerator, or for a longer period in the freezer, after being blanched quickly in boiling water. The dried herb also loses most of its flavor, and what little flavor remains tastes very different.9oo *oo" ), LGTeacher( name: "Kody", license: "http://creativecommons.org/licenses/by-sa/3.0", credit: "http://commons.wikimedia.org/wiki/User:Lin%C3%A91", description: "Saffron's aroma is often described by connoisseurs as reminiscent of metallic honey with grassy or hay-like notes, while its taste has also been noted as hay-like and sweet. Saffron also contributes a luminous yellow-orange colouring to foods. Saffron is widely used in Indian, Persian, European, Arab, and Turkish cuisines. Confectioneries and liquors also often include saffron." ), LGTeacher( name: "Hank", license: "http://creativecommons.org/licenses/by-sa/3.0", credit: "http://commons.wikimedia.org/wiki/User:Raul654", description: "Marjoram is used for seasoning soups, stews, dressings and sauce. Majorana has been scientifically proved to be beneficial in the treatment of gastric ulcer, hyperlipidemia and diabetes. Majorana hortensis herb has been used in the traditional Austrian medicine for treatment of disorders of the gastrointestinal tract and infections." ), LGTeacher( name: "CC", license: "http://www.gnu.org/licenses/old-licenses/fdl-1.2.html", credit: "http://commons.wikimedia.org/wiki/User:Fir0002", description: "The leaves, both fresh and dried, are used in traditional Italian cuisine. They have a bitter, astringent taste and are highly aromatic, which complements a wide variety of foods. Herbal tea can be made from the leaves. When burnt, they give off a mustard-like smell and a smell similar to burning wood, which can be used to flavor foods while barbecuing. Rosemary is high in iron, calcium and vitamin B6.") , LGTeacher( name: "Cat", license: "http://commons.wikimedia.org/wiki/File:AniseSeeds.jpg", credit: "http://commons.wikimedia.org/wiki/User:Ben_pcc", description: "Anise is sweet and very aromatic, distinguished by its characteristic flavor. The seeds, whole or ground, are used in a wide variety of regional and ethnic confectioneries, including black jelly beans, British aniseed balls, Australian humbugs, and others. The Ancient Romans often served spiced cakes with aniseseed, called mustaceoe at the end of feasts as a digestive. " ) ] } }
匹配包含
LG
的内容grep "LG" test.swift ------------------------- struct LGTeacher { struct LGTeachers { extension LGTeacher { static var all: [LGTeacher] { [ LGTeacher( LGTeacher( LGTeacher( LGTeacher( LGTeacher(
匹配包含
LG
的内容,将每一行的匹配结果,都向下多显示一行grep "LG" test.swift -A 1 ------------------------- struct LGTeacher { let name: String -- struct LGTeachers { let name: String -- extension LGTeacher { static var all: [LGTeacher] { [ LGTeacher( name: "Cooci", -- LGTeacher( name: "Kody", -- LGTeacher( name: "Hank", -- LGTeacher( name: "CC", -- LGTeacher( name: "Cat",
匹配包含
LG
的内容,将每一行的匹配结果,上下各多显示一行grep "LG" test.swift -A 1 -B 1 ------------------------- struct LGTeacher { let name: String -- -- struct LGTeachers { let name: String -- -- extension LGTeacher { static var all: [LGTeacher] { [ LGTeacher( name: "Cooci", -- -- ), LGTeacher( name: "Kody", -- -- ), LGTeacher( name: "Hank", -- -- ), LGTeacher( name: "CC", -- -- , LGTeacher( name: "Cat",
匹配包含
lgteacher
的内容,忽略大小写grep "lgteacher" test.swift -i ------------------------- struct LGTeacher { struct LGTeachers { extension LGTeacher { static var all: [LGTeacher] { [ LGTeacher( LGTeacher( LGTeacher( LGTeacher( LGTeacher(
匹配过滤
LGTeacher
后的内容grep "LGTeacher" test.swift -v
匹配包含
LGTeacher
的内容,但不匹配LGTeachers
grep "LGTeacher[^s]" test.swift ------------------------- struct LGTeacher { extension LGTeacher { static var all: [LGTeacher] { [ LGTeacher( LGTeacher( LGTeacher( LGTeacher( LGTeacher(
匹配包含
oo
的内容grep "oo" test.swift
匹配包含
oo
的内容,过滤前面由小写字母开头的内容grep "[^a-z]oo" test.swift //或者 grep "[^[:lower:]]oo" test.swift
匹配包含
oo
的内容,只保留数字或符号开头的内容grep "[^A-Za-z]oo" test.swift
匹配包含
oo
的内容,只保留数字开头的内容grep "[0-9]oo" test.swift //或者 grep "\doo" test.swift
匹配包含
oo
的内容,只保留符号开头的内容grep "[^A-Za-z0-9]oo" test.swift //或者 grep "\Woo" test.swift
匹配包含
oo
的内容,过滤前面由符号开头的内容grep "[A-Za-z0-9]oo" test.swift //或者 grep "\woo" test.swift
使用
.
占中间两位,匹配C
开头,ci
结尾的内容grep "C..ci" test.swift ------------------------- name: "Cooci",
匹配
C
开头,使用.
占后两位的内容grep "C.." test.swift
.
:匹配所有的字符,除了newline
和null
匹配
Co
开头,使用*
占后一位的内容grep "Co*" test.swift
*
:匹配前⼀个元素0
次或多次
匹配
Coo
开头,使用*
占后一位的内容grep "Coo*" test.swift
匹配
C
开头,后面接两个o
的内容grep -E "Co{2}" test.swift ------------------------- name: "Cooci",
- 间隔操作符
{ ... }
,是ERE
中支持的特殊符号。grep
命令支持ERE
表达式,需要增加-E
参数
分组与向后引⽤
分组\捕获组操作符
(( ... ) or \( ... \))
:
- 定义⼀个⼦表达式。正则表达式将此序列视为⼀个单元。圆括号在整体匹配完后进⾏匹配
- 可以配合反向引⽤操作符,重复使⽤分组匹配的结果
反向引⽤操作符
(\digit)
:
- 反向引⽤操作符由
\数字
表示,数字需介于1-9
,代表引⽤那个分组的匹配结果
案例1:
匹配包含
oo
的内容,只保留数字开头的内容,使用(\d)
进行分组grep -E "(\d)oo" test.swift
- 分组
( ... )
,是ERE
中支持的特殊符号。grep
命令支持ERE
表达式,需要增加-E
参数
案例2:
通过
\1
获取第一个分组内容grep -E "description(.*)(\1)" test.swift
- 反向引⽤操作符
(\digit)
,代表引⽤那个分组的匹配结果
\ 字符
以下内容在部分语⾔中不⽀持
每种环境,⽆论是
Python
、Perl
、Java
、C#
、Ruby
还是其他,在实现正则表达式时都有特殊的差别。Swift
也不例外
Objective-C
和Swift
都要求您转义⽂字字符串中的特殊字符(即,在它们
前⾯加反斜杠\
字符)。反斜杠本身就是这样的特殊字符之⼀。由于⽤于创建
正则表达式的模式也是字符串,因此会增加复杂性,因为在使⽤Stringand
时
需要转义反斜杠字符NSRegularExpression
这意味着标准正则表达式
\.
将出现\\.
在您的Swift
(或Objective-C
)代码中
- ⽂字
\\.
定义了⼀个类似于以下字符串:\.
- 正则表达式
\.
然后将匹配单个句点字符
贪婪模式
贪婪模式、勉强模式与侵占模式:
贪婪匹配 勉强匹配 侵占匹配 作⽤ X?
X??
X?+
匹配 X
零次或⼀次X*
X*?
X*+
匹配 X
零次或多次X+
X+?
X++
匹配 X
⼀次或多次X{n}
X{n}?
X{n}+
匹配 X
,n
次X{n,}
X{n,}?
X{n,}+
匹配 X
⾄少n
次X{n,m}
X{n,m}?
X{n,m}+
匹配 X
⾄少n
次,但不多于m
次
案例1:
匹配
test.swift
文件中,description
相关内容
grep "description.*\"$" test.swift //或者 grep -E "description(.*)[\"]$" test.swift
案例2:
假定要分析的字符串是
xfooxxxxxxfoo
模式
.*foo
(贪婪模式)由两部分
p1
:(.*)
p2
:(foo)
查看匹配结果,其中
p1
中的匹配⽅式使⽤默认⽅式(贪婪型)
- 第⼀轮:匹配开始时,
p1
匹配所有字符xfooxxxxxx
,匹配成功,但p2
⽆匹配字符,本轮匹配失败- 第⼆轮:减少
p1
部分的匹配量,留出最后⼀个字符, 此时存在两个字符串,s1
代表xfooxxxxxxfo
和s2
代表o
。s1
匹配p1
, 但s2
不匹配p2
。本轮匹配失败- 第三轮,继续减少
p1
匹配量,留出两个字符, 字符串被分割成xfooxxxxxxfo
和oo
两部分。结果同上- 第四轮,再次减少
p1
匹配量,字符串分割成xfooxxxxxx
和foo
两个部分,这次p1/p2
同时匹配。返回匹配成功
案例3:
模式
.*?foo
(勉强模式)最⼩匹配⽅式
p1
:(.*?)
p2
:(foo)
查看匹配结果,其中
p1
中的匹配⽅式使⽤勉强模式匹配
- 第⼀轮:
p1
由于是0
或任意次,⾸先匹配0
次。所以直接⽤字符串去匹配p2
,但p2
⽆匹配字符,本轮匹配失败- 第⼆轮:增加
p1
部分的匹配量,匹配x
。此时存在两个字符串,s1
代表x
和s2
代表fooxxxxxxfoo
。s1
匹配p1
, 但s2
不匹配p2
。本轮匹配失败;继续上述匹配直到满⾜p2
案例4:
模式
.*+foo
(侵占模式)
p1
:(.*+)
p2
:(foo)
查看匹配结果,其中
p1
中的匹配⽅式使⽤侵占模式匹配
- 匹配开始时读⼊所有字符串,和
p1
匹配成功,但没有剩余字符串去和p2
匹配。匹配失败
简单地说,贪婪模式和侵占模式相⽐,贪婪模式会在只有部分匹配成功的条件下,依次从多到少减少匹配成功部分模式的匹配数量,将字符留给模式其他部分去匹配。⽽侵占模式则是占有所有能匹配成功部分,绝不留给其他部分使⽤
案例5:
使用
(fooq|foo)*(qbarquux|bar)
完全匹配的字符串是?
A
、fooqbarquuxB
、fooqbarC
、以上都选仅选项
B
可以完全匹配,选项A
只能匹配出fooqbar
前半部分
案例6:
使用
((a*)b)*\1\2
完全匹配的字符串是?
A
、aabababaB
、aabaabaabaabaaC
、以上都选答案为选项
C
,选项A
和B
都可以完全匹配
- 如果分组不⽌⼀次匹配(例如,如果后⾯跟着重复运算符),则
向后引⽤将匹配分组最后匹配的⼦字符串
案例7:
使用
(one(x)|two(y))-and-(three\2|four\3)
完全匹配的字符串是?
A
、onex-and-threexB
、twoy-and-fouryC
、onex-and-fourD
、twoy-and-threeyE
、twoy-and-threex选项
A
和B
都可以完全匹配
- 分组
\2
、\3
分别对应(x)
、(y)
,当(x)
匹配失败,分组\2
的位置存在,但分组报错- 当访问报错的分组,匹配将会中断
案例8:
在
t.swift
文件中,删除description
节点
使用
description:(\W)(.*)
将匹配的内容替换为空
结尾的渣男操作符
.
,除newline
和null
匹配所有字符
案例9:
将
license
和credit
的值,都改为https://www.baidu.com/
使用
(license|credit):[\W](.)*
将匹配的内容替换为$1: "https://www.baidu.com/",
$1
表示分组\1
的(license|credit)
更⾼级的⽤法
零宽断⾔
断⾔:在指定位置应该满⾜⼀定的条件
当捕获组以开头时
?=
,表示该组将被⽤作零宽度正预测先⾏断⾔,仅当前⼀个模式与捕获组中的模式相匹配时才与前⼀个模式匹配。例如,A(?=B)
与A
匹配,并且⻢上跟着B
。可以匹配AB
、ABB
、ACB
Unicode
匹配特定类别的
Unicode
字符\p{ ... }
:
\p{L}
所有字符,\p{Lu}
所有⼩写字符,\p{N}
\P{}
匹配不特定类别的Unicode
字符
sed命令
sed
命令:可以将数据进⾏替换、删除、新增、选取特定内容等功能,⽤作⼀整⾏字符处理
命令格式
sed [options] 'command' file(s) sed [options] -f scriptfile file(s)
选项
-e