作者:IvanCodes
日期:2025年8月11日
专栏:Linux教程
正则表达式的本质是一套用于描述和匹配字符串集合规则的模式语言。 它通过组合普通字符和具有特殊含义的元字符 来定义一个"模板",然后用这个模板去文本中进行模式匹配。
一、基本匹配 (字面量匹配)
最基础的正则表达式就是字符串本身,它会精确匹配文本中完全相同的字符序列。
代码示例 (使用 grep 命令演示):
bash
# 在字符串中查找 "cat"
echo "My cat is black, your cat is white." | grep --color=always 'cat'
(--color=always 用于高亮匹配部分。为防止Shell对特殊字符进行解释,强烈建议将正则表达式用单引号 '' 包裹。)
二、核心元字符
正则表达式的威力来源于元字符,这些字符不再代表其字面含义,而是被赋予了特殊的匹配功能。
1.. (点) - 匹配任意单个字符
一个点 . 可以代表除换行符外的任何一个字符。
bash
# 匹配 "c" 和 "t" 之间有任意一个字符的模式
echo "cat cot c-t c@t chart" | grep --color=always 'c.t'
# 将匹配 cat, cot, c-t, c@t
2.* (星号) - 匹配前一个元素零次或多次
星号 * 表示其紧邻的前一个字符或分组可以出现任意次数 (0, 1, 2, ...)。
bash
# 匹配 "go" 和 "gle" 之间有任意数量 "o" 的模式
echo "ggle google goooogle gogle" | grep --color=always 'go*gle'
# 将匹配 ggle (o出现0次), google, goooogle
3.+ (加号) - 匹配前一个元素一次或多次
加号 + 与星号类似,但要求其前一个元素至少出现一次 (1, 2, 3, ...)。
bash
# 匹配 "go" 和 "gle" 之间至少有一个 "o" 的模式
echo "ggle google goooogle gogle" | grep -E --color=always 'go+gle'
# 将匹配 google, goooogle,但不匹配 ggle
注意 - 正则表达式方言 (Flavor):
像 +, ?, |, () 等元字符,在基础正则表达式 (BRE) 中 (如标准 grep) 需要前置反斜杠 \ (如 \+) 才能生效。而在扩展正则表达式 (ERE) 中 (如 grep -E 或 egrep) 则直接使用。为方便和现代,本教程的示例主要使用 ERE。
4.? (问号) - 匹配前一个元素零次或一次
问号 ? 表示其前一个元素是可选的。
bash
# 匹配 "color" 和 "colour"
echo "color colour counselor" | grep -E --color=always 'colou?r'
5.^ (尖角号) - 匹配行首
当 ^ 位于正则表达式的开头时,它锚定匹配必须从一行的开始处发生。
bash
# 匹配以 "start" 开头的行
echo -e "start of the line\nmiddle start end" | grep -E --color=always '^start'
# 只会匹配第一行
6.$ (美元符) - 匹配行尾
当 $ 位于正则表达式的末尾时,它锚定匹配必须在一行的结束处结束。
bash
# 匹配以 "end" 结尾的行
echo -e "the line must end\nend of the line" | grep -E --color=always 'end$'
# 只会匹配第一行
组合使用 ^ 和 $ 可以进行整行匹配。例如 ^root$ 只匹配内容仅为 "root" 的行。
7.[...] (方括号) - 匹配字符集合
方括号 [...] 定义了一个字符集,它会匹配集合内的任意一个字符。
[abc]: 匹配 'a', 'b', 'c' 中的一个。
[0-9]: 匹配任意一个数字。
[a-z]: 匹配任意一个小写字母。
[a-zA-Z]: 匹配任意一个字母。
[^abc]: (当^在方括号内开头时) 反向匹配,匹配除 'a', 'b', 'c' 之外的任意一个字符。
bash
# 匹配 "log" 后跟任意一个数字,然后是 ".txt"
echo "log1.txt logA.txt log-3.txt" | grep -E --color=always 'log[0-9]\.txt'
# 将匹配 log1.txt
8.\ (反斜杠) - 转义元字符
反斜杠 \ 用于去除其后元字符的特殊含义,使其变回字面字符。例如,要匹配一个真正的点 .,必须写成 \.。
三、量词与分组
1. 精确量词 {}
花括号 {} 用于精确控制其前一个元素的重复次数。
{n}: 正好 n 次。{n,}: 至少 n 次。{n,m}: n 到 m 次 (包含n和m)。
bash
# 匹配一个4位数的年份
echo "Date: 2024, Item: 123" | grep -E --color=always '[0-9]{4}'
# 将匹配 2024
2. 分组 () 与或 |
- 圆括号
(): 将多个字符组合成一个逻辑单元,可以对整个单元应用量词。默认情况下,()还会捕获其匹配到的内容,用于后续引用。 - 竖线
|: 表示"或"关系,匹配其左边或右边的表达式。
bash
# 匹配 "file.log" 或 "file.txt"
echo "file.log file.txt file.dat" | grep -E --color=always 'file\.(log|txt)'
# 匹配 "http://" 或 "https://", 后跟任意字符
echo "URL: https://example.com" | grep -E --color=always '(http|https)://.*'
四、常见应用场景与工具
正则表达式在Linux命令行中无处不在:
grep: 文本搜索。sed: 流编辑器,用于文本替换和转换。awk: 强大的文本处理语言。find:-regex选项支持基于路径的正则匹配。- 文本编辑器 :
vim,emacs等都内置了强大的正则搜索/替换功能。 - 编程语言 : Python (
re), Perl, JavaScript (RegExp), Java (java.util.regex) 等几乎所有语言都提供了正则库。
五、更多信息
- POSIX 字符类 : 为了更好的可移植性和对非ASCII字符的支持,可以使用
[[:...:]]形式的字符类,例如[[:digit:]]等同于[0-9],[[:alpha:]]等同于[a-zA-Z]。 - 贪婪与非贪婪匹配 : 默认情况下,像
*和+这样的量词是贪婪的,即它们会尽可能多地匹配字符。在支持PCRE (Perl Compatible Regular Expressions) 的引擎中 (如grep -P),可以在量词后添加?(如*?,+?) 来切换到非贪婪模式,即尽可能少地匹配。
总结: 正则表达式是处理和分析文本数据的基石。从简单的字面量匹配,到组合使用元字符、量词、分组和锚点,可以构建出极其精确和灵活的匹配模式。熟练掌握正则表达式将极大地提升你在命令行和脚本编程中的工作效率。
练习题
题目一:基本匹配与元字符
写一个正则表达式,匹配包含 color 或 colour 这两个单词的行。
题目二:数字匹配
写一个正则表达式,匹配一个三位数的整数。
题目三:开头与结尾
写一个正则表达式,匹配以大写字母开头,并且以句号 . 结尾的整行。
题目四:字符集合
写一个正则表达式,匹配一个小写元音字母 (a, e, i, o, u)。
题目五:量词
写一个正则表达式,匹配一个由至少两个数字组成的字符串。
题目六:转义
写一个正则表达式来精确匹配字符串 127.0.0.1。
题目七:分组与或
写一个正则表达式,匹配 apple.jpg 或 apple.png。
题目八:综合应用 (简单邮箱格式)
写一个非常简化的正则表达式,尝试匹配类似 user@example.com 格式的字符串(假设用户名和域名只包含字母、数字、下划线,并且域名只有两部分)。
题目九:反向匹配
写一个正则表达式,匹配不包含任何数字的行。
题目十:POSIX字符类
使用POSIX字符类,写一个正则表达式,匹配一个或多个十六进制字符 (0-9, a-f, A-F)。
答案与解析
答案一:
regex
colou?r
- 解析:
?量词表示其前一个字符 (u) 可以出现0次或1次,因此可以同时匹配color和colour。
答案二:
regex
[0-9]{3}
- 解析:
[0-9]匹配任意一个数字,{3}这个量词表示前面的元素必须正好出现3次。如果要求整行就是三位数,应写成^[0-9]{3}$。
答案三:
regex
^[A-Z].*\.$
- 解析:
^匹配行首,[A-Z]匹配一个大写字母,.*匹配任意数量的任意字符,\.匹配一个字面上的点,$匹配行尾。
答案四:
regex
[aeiou]
- 解析:
[...]字符集会匹配其中列出的任意一个字符。
答案五:
regex
[0-9]{2,}
- 解析:
{2,}量词表示前面的元素 ([0-9]) 必须出现至少2次。
答案六:
regex
127\.0\.0\.1
- 解析: IP地址中的点
.是元字符,必须使用反斜杠\进行转义,才能匹配其字面含义。
答案七:
regex
apple\.(jpg|png)
- 解析:
\.匹配点。(jpg|png)使用分组()和或|来匹配jpg或png字符串。
答案八:
regex
[a-zA-Z0-9_]+@[a-zA-Z0-9_]+\.[a-zA-Z0-9_]+
- 解析:
[a-zA-Z0-9_]+匹配至少一个字母、数字或下划线,用于匹配用户名和域名部分。@和\.匹配字面符号。这是一个简化模型。
答案九:
regex
^[^0-9]*$
- 解析:
^和$锚定整行。[^0-9]是一个反向字符集,匹配任何非数字字符。*表示这些非数字字符可以出现任意次数 (包括0次,以匹配空行)。
答案十:
regex
[[:xdigit:]]+
- 解析:
[[:xdigit:]]是POSIX字符类,专门用于匹配十六进制字符 (等效于[0-9a-fA-F])。+表示匹配一次或多次。使用POSIX字符类可读性更好且兼容性更强。