正则表达式

正则表达式定义:由一系列特定字符组成的字符串,用来匹配目标文本中符合指定条件的字符或者字符串。

在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码

8.正则表达式-2023-06-16-21-24-50

如果你想查找某个目录下的所有的Word文档的话,你会搜索*.doc。在这里,*会被解释成任意的字符串。和通配符类似,正则表达式也是用来进行文本匹配的工具,只不过比起通配符,它能更精确地描述你的需求——当然,代价就是更复杂——比如你可以编写一个正则表达式,用来查找所有以0开头,后面跟着2-3个数字,然后是一个连字号”-“,最后是7或8位数字的字符串(像010-123456780376-7654321)。

入门

正则表达式练习平台:https://www.jyshare.com/front-end/854/

最简单的正则表达式举例: hi ,它可以精确匹配由两个字符组成,前一个字符是 h,后一个是 i 的字符串。常用的处理工具(如 grep)通常提供忽略大小写的选项 -i

# 演示:忽略大小写匹配 hi
ubuntu@sh:~$ echo "hi,Hi,HI,hI" | grep -i "hi"
[匹配结果] hi,Hi,HI,hI

元字符

当目标文本中包含很多字符,比如him,history,high等等。用hi来查找的话,这里边的hi也会被找出来。如果要精确地查找hi这个单词的话,我们应该使用\bhi\b。\b是正则表达式规定的一个特殊代码(元字符,metacharacter),代表着单词的开头或结尾,也就是单词的分界处。

假如要找的是hi后面不远处跟着一个Lucy,应该用\bhi\b.*\bLucy\b

这里,.是另一个元字符,匹配除了换行符以外的任意字符。同样是元字符,不过它代表的不是字符,也不是位置,而是数量——它指定*前边的内容可以连续重复使用任意次以使整个表达式得到匹配。因此,.连在一起就意味着任意数量的不包含换行的字符。现在\bhi\b.*\bLucy\b的意思就很明显:先是一个单词hi,然后是任意个任意字符(但不能是换行),最后是Lucy这个单词。

  • 常用的元字符
代码 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束

元字符 ^(行首)和 $(行尾)都匹配一个位置。它们在验证输入时非常有用,例如要求填写的 QQ 号必须为 5 到 12 位纯数字:^\d{5,12}$

# 演示:使用 -o 选项只查看匹配到的内容部分
ubuntu@sh:~$ echo "hi,Hi,HI,hI,Lucy" | grep -o "\bhi\b.*\bLucy\b"
[找到目标] hi,Hi,HI,hI,Lucy
  • 如何匹配像010-123456780376-7654321格式的数字?

    0\d\d-\d\d\d\d\d\d\d\d匹配这样的字符串:以0开头,然后是两个数字,然后是一个连字号“-”,最后是8个数字(也就是中国的电话号码)。这里的\d是个新的元字符,匹配一位数字(0,或1,或2,或……)。-不是元字符,只匹配它本身——连字符。

    也可以这样写这个表达式:0\d{2}-\d{8}。这里\d后面的{2}({8})的意思是前面\d必须连续重复匹配2次(8次)

作业1:在一组格式为区号-8位数字的国内电话号码中匹配无锡市的电话号码,无锡的区号是051

  • 常用的限定符
代码/语法 说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
  1. \ba\w*\b匹配以字母a开头的单词——先是某个单词开始处(\b),然后是字母a,然后是任意数量的字母或数字(\w*),最后是单词结束处(\b)
  2. \d+匹配1个或更多连续的数字。这里的+是和类似的元字符,不同的是匹配重复任意次(可能是0次),而+则匹配重复1次或更多次。
  3. \b\w{6}\b 匹配刚好6个字符的单词。

字符转义

如果想查找元字符本身的话,比如查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时就得使用\来取消这些字符的特殊意义。因此,应该使用\.\*。当然,要查找\本身,也得用\\.

例如:deerchao\.cn匹配deerchao.cnC:\\Windows匹配C:\Windows

字符类

要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集合的元字符,但是如果想匹配没有预定义元字符的字符集合,需要在方括号中列出他们:[aeiou]就匹配任何一个英文元音字母,[.?!]匹配标点符号(.或?或!)。

作业2:使用正则表达式匹配符合邮箱格式的信息。邮箱由大小写字母、数字构成,如:1234abc@23abc.sd

分组

想要重复多个字符又该怎么办?可以用小括号来指定子表达式(也叫做分组),然后就可以指定这个子表达式的重复次数了。(\d{1,3}\.){3}\d{1,3}是一个简单的IP地址匹配表达式。要理解这个表达式,按下列顺序分析它:

  1. \d{1,3}匹配1到3位的数字
  2. (\d{1,3}\.){3}匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复3次
  3. 最后再加上一个一到三位的数字(\d{1,3})

它也将匹配256.300.888.999这种不可能存在的IP地址。如果能使用算术比较的话,或许能简单地解决这个问题,但是正则表达式中并不提供关于数学的任何功能,所以只能使用冗长的分组,选择,字符类来描述一个正确的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

理解这个表达式的关键是理解2[0-4]\d|25[0-5]|[01]?\d\d?

反义

有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义

代码/语法 说明
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符

例子:\S+匹配不包含空白符的字符串。

<a[^>]+>匹配用尖括号括起来的以a开头的字符串。

贪婪与懒惰

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索*aabab*的话,它会匹配整个字符串aabab。这被称为贪婪匹配。

有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。

举例:a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于*aabab*的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。

代码/语法 说明
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

作业1:使用懒惰匹配匹配以下文本中<strong>标签中的内容。

`<p>This is a <strong>sample</strong> text with <strong>multiple</strong> <strong>tags</strong>.</p>`

grep命令

grep基本用法

Linux grep (global search regular expression and print out the line) 命令用于查找文件里符合条件的字符串或正则表达式。

grep 指令用于查找内容包含指定的范本样式的文件,如果发现某文件的内容符合所指定的范本样式,预设 grep 指令会把含有范本样式的那一列显示出来。若不指定任何
文件名称,或是所给予的文件名为 -,则 grep 指令会从标准输入设备读取数据。

  • 基于目标文件查找包含 “ubuntu” 的行:

    ubuntu@sh:~$ grep "ubuntu" /etc/passwd
    [匹配行] ubuntu:x:1000:1000:ubuntu,,,:/home/ubuntu:/bin/bash
  • 通过管道符号处理进程列表(查找 SSH 服务):

    ubuntu@sh:~$ ps -aux | grep ssh
    [进程] root        864  0.0  0.1  /usr/sbin/sshd -D
    [进程] ubuntu    23726  0.0  0.0  grep --color=auto ssh
  • 常见选项功能说明

    • -i:忽略大小写进行搜索。
    • -v:反向查找,排除包含关键词的行。
    • -n:在输出中附加行的编号。
    • -r:在当前目录下递归搜索文件内容。
    • -l:仅列出包含关键词的文件路径。
    • -c:仅统计匹配到的行数总额。

grep结合正则表达式用法

  • 已有文本文件example.txt,其中存储了一些人的信息,包括姓名、年龄和职业,每行一个人的信息:

    John Smith, 25, Engineer
    Alice Brown, 30, Teacher
    Bob Johnson, 40, Lawyer

    查找年龄在 30 岁及以上的人的信息,可以使用以下命令:

    # [过滤] 查找年龄 30 及以上的记录grep '[3-9][0-9],.*' example.txt
    Alice Brown, 30, Teacher
    Bob Johnson, 40, Lawyer
  • 找出~目录下以.sh结尾的文件名

    # [提取] 仅输出文件名,不包含路径find ~ -name "*.sh" | grep -Eo "[^/]+\.sh"
    test.sh
    check.sh

作业2:显示当前系统中禁止登录的用户名。可以通过匹配文件/etc/passwd中以/usr/sbin/nologin结尾的行,只输出对应的用户名。