正则表达式全解析:基础、扩展与实战应用
1. 正则表达式基础
1.1 精确匹配数字
若要确保仅匹配五个数字,需对其进行界定,可使用空格,或者指定它们位于行首和行尾。示例如下:
$ sed -n '
> /^[0123456789][0123456789][0123456789][0123456789][0123456789]$/p
> ' data8
60633
46201
22203
$
1.2 字符类的应用
字符类在解析可能拼写错误的单词时极为有用,例如处理用户表单输入的数据。可轻松创建正则表达式来接受数据中常见的拼写错误。示例如下:
$ cat data9
I need to have some maintenence done on my car.
I'll pay that in a seperate invoice.
After I pay for the maintenance my car will be as good as new.
$ sed -n '
/maint[ea]n[ae]nce/p
/sep[ea]r[ea]te/p
' data9
I need to have some maintenence done on my car.
I'll pay that in a seperate invoice.
After I pay for the maintenance my car will be as good as new.
$
此例中的两个
sed
打印命令利用正则表达式字符类,成功捕获了文本中拼写错误的单词 “maintenance” 和 “separate”,同时该正则表达式模式也能匹配正确拼写的 “maintenance”。
1.3 否定字符类
在正则表达式模式中,可反转字符类的作用。不查找字符类中包含的字符,而是查找不在该类中的任何字符。只需在字符类范围的开头放置一个脱字符即可。示例如下:
$ sed -n '/[^ch]at/p' data6
This test is at line four.
$
通过否定字符类,正则表达式模式匹配既不是 “c” 也不是 “h” 的任何字符,以及文本模式。由于空格字符符合此类别,因此它通过了模式匹配。不过,即使进行了否定,字符类仍必须匹配一个字符,所以行首带有 “at” 的行仍不匹配该模式。
1.4 使用范围
之前展示的邮政编码示例中,在每个字符类中列出所有可能的数字较为繁琐。可使用破折号符号在字符类中指定字符范围,即指定范围的第一个字符、破折号,然后是范围的最后一个字符。正则表达式将包含指定字符范围内的任何字符,具体取决于 Linux 系统使用的字符集。
简化后的邮政编码示例如下:
$ sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p' data8
60633
46201
45902
$
此方法节省了大量输入。每个字符类匹配 0 到 9 的任何数字。若数据中任何位置出现字母,模式匹配将失败。
字母范围的使用示例如下:
$ sed -n '/[c-h]at/p' data6
The cat is sleeping.
That is a very nice hat.
$
新模式 “[c - h]at” 匹配首字母在 “c” 和 “h” 之间的单词。在此情况下,仅包含单词 “at” 的行不匹配该模式。
还可在单个字符类中指定多个不连续的范围,示例如下:
$ sed -n '/[a-ch-m]at/p' data6
The cat is sleeping.
That is a very nice hat.
$
该字符类允许 “a” 到 “c” 以及 “h” 到 “m” 的范围出现在 “at” 文本之前。此范围将拒绝 “d” 到 “g” 之间的任何字母。
1.5 特殊字符类
除了定义自己的字符类外,BRE 包含可用于匹配特定类型字符的特殊字符类。具体如下表所示:
| 类 | 描述 |
| — | — |
| [[:alpha:]] | 匹配任何字母字符,包括大写或小写 |
| [[:alnum:]] | 匹配任何字母数字字符 0 - 9、A - Z 或 a - z |
| [[:blank:]] | 匹配空格或制表符 |
| [[:digit:]] | 匹配 0 到 9 的数字 |
| [[:lower:]] | 匹配任何小写字母字符 a - z |
| [[:print:]] | 匹配任何可打印字符 |
| [[:punct:]] | 匹配标点字符 |
| [[:space:]] | 匹配任何空白字符:空格、制表符、换行符、换页符、垂直制表符、回车符 |
| [[:upper:]] | 匹配任何大写字母字符 A - Z |
使用特殊字符类的示例如下:
$ echo "abc" | sed -n '/[[:digit:]]/p'
$
$ echo "abc" | sed -n '/[[:alpha:]]/p'
abc
$ echo "abc123" | sed -n '/[[:digit:]]/p'
abc123
$ echo "This is, a test" | sed -n '/[[:punct:]]/p'
This is, a test
$ echo "This is a test" | sed -n '/[[:punct:]]/p'
$
使用特殊字符类是定义范围的简便方法,例如可直接使用
[[:digit:]]
替代
[0 - 9]
。
1.6 星号的使用
在字符后放置星号表示该字符在文本中必须出现零次或多次才能匹配模式。示例如下:
$ echo "ik" | sed -n '/ie*k/p'
ik
$ echo "iek" | sed -n '/ie*k/p'
iek
$ echo "ieek" | sed -n '/ie*k/p'
ieek
$ echo "ieeek" | sed -n '/ie*k/p'
ieeek
$ echo "ieeeek" | sed -n '/ie*k/p'
ieeeek
$
此模式符号常用于处理常见拼写错误或语言拼写变化的单词。例如,编写可能用于美式或英式英语的脚本时,可如下编写:
$ echo "I'm getting a color TV" | sed -n '/colou*r/p'
I'm getting a color TV
$ echo "I'm getting a colour TV" | sed -n '/colou*r/p'
I'm getting a colour TV
$
模式中的
u*
表示字母 “u” 可能在文本中出现,也可能不出现以匹配模式。同样,若知道某个单词常见的拼写错误,可使用星号来处理,示例如下:
$ echo "I ate a potatoe with my lunch." | sed -n '/potatoe*/p'
I ate a potatoe with my lunch.
$ echo "I ate a potato with my lunch." | sed -n '/potatoe*/p'
I ate a potato with my lunch.
$
在可能的额外字母旁边放置星号,可接受拼写错误的单词。
将点特殊字符与星号特殊字符结合使用,可提供匹配任意数量任意字符的模式,常用于可能不在数据流中相邻出现的两个文本字符串之间。示例如下:
$ echo "this is a regular pattern expression" | sed -n '
> /regular.*expression/p'
this is a regular pattern expression
$
使用此模式,可轻松搜索数据流中一行文本中可能出现在任何位置的多个单词。
星号也可应用于字符类,允许指定可在文本中多次出现的字符组或范围。示例如下:
$ echo "bt" | sed -n '/b[ae]*t/p'
bt
$ echo "bat" | sed -n '/b[ae]*t/p'
bat
$ echo "bet" | sed -n '/b[ae]*t/p'
bet
$ echo "btt" | sed -n '/b[ae]*t/p'
btt
$ echo "baat" | sed -n '/b[ae]*t/p'
baat
$ echo "baaeeet" | sed -n '/b[ae]*t/p'
baaeeet
$ echo "baeeaeeat" | sed -n '/b[ae]*t/p'
baeeaeeat
$ echo "baakeeet" | sed -n '/b[ae]*t/p'
$
只要 “a” 和 “e” 字符以任何组合出现在 “b” 和 “t” 字符之间(包括根本不出现),模式就匹配。若定义的字符类之外的任何其他字符出现,模式匹配将失败。
2. 扩展正则表达式
2.1 问号
问号与星号类似,但有细微差别。问号表示前面的字符可以出现零次或一次,但仅此而已,它不匹配字符的重复出现。示例如下:
$ echo "bt" | gawk '/be?t/{print $0}'
bt
$ echo "bet" | gawk '/be?t/{print $0}'
bet
$ echo "beet" | gawk '/be?t/{print $0}'
$
$ echo "beeet" | gawk '/be?t/{print $0}'
$
若 “e” 字符不在文本中出现,或者只要它在文本中仅出现一次,模式就匹配。
与星号一样,可将问号符号与字符类一起使用。示例如下:
$ echo "bt" | gawk '/b[ae]?t/{print $0}'
bt
$ echo "bat" | gawk '/b[ae]?t/{print $0}'
bat
$ echo "bot" | gawk '/b[ae]?t/{print $0}'
$
$ echo "bet" | gawk '/b[ae]?t/{print $0}'
bet
$ echo "baet" | gawk '/b[ae]?t/{print $0}'
$
$ echo "beat" | gawk '/b[ae]?t/{print $0}'
$
$ echo "beet" | gawk '/b[ae]?t/{print $0}'
$
若字符类中的零个或一个字符出现,模式匹配通过。然而,若两个字符都出现,或者其中一个字符出现两次,模式匹配将失败。
2.2 加号
加号是另一个与星号类似的模式符号,但与问号有不同的差别。加号表示前面的字符可以出现一次或多次,但必须至少出现一次。若字符不存在,模式不匹配。示例如下:
$ echo "beeet" | gawk '/be+t/{print $0}'
beeet
$ echo "beet" | gawk '/be+t/{print $0}'
beet
$ echo "bet" | gawk '/be+t/{print $0}'
bet
$ echo "bt" | gawk '/be+t/{print $0}'
$
若 “e” 字符不存在,模式匹配失败。加号也可与字符类一起使用,示例如下:
$ echo "bt" | gawk '/b[ae]+t/{print $0}'
$
$ echo "bat" | gawk '/b[ae]+t/{print $0}'
bat
$ echo "bet" | gawk '/b[ae]+t/{print $0}'
bet
$ echo "beat" | gawk '/b[ae]+t/{print $0}'
beat
$ echo "beet" | gawk '/b[ae]+t/{print $0}'
beet
$ echo "beeat" | gawk '/b[ae]+t/{print $0}'
beeat
$
若字符类中定义的任何一个字符出现,文本就匹配指定的模式。
2.3 使用花括号
在 ERE 中,可使用花括号指定可重复正则表达式的限制,这通常称为间隔。可通过以下两种格式表达间隔:
-
m
:正则表达式恰好出现
m
次。
-
m,n
:正则表达式至少出现
m
次,但不超过
n
次。
此功能允许精确调整允许字符(或字符类)在模式中出现的次数。
默认情况下,
gawk
不识别正则表达式间隔,必须指定
--re-interval
命令行选项,
gawk
才能识别正则表达式间隔。
使用单个值间隔的示例如下:
$ echo "bt" | gawk --re-interval '/be{1}t/{print $0}'
$
$ echo "bet" | gawk --re-interval '/be{1}t/{print $0}'
bet
$ echo "beet" | gawk --re-interval '/be{1}t/{print $0}'
$
通过指定间隔为 1,限制了字符为使字符串匹配模式而必须出现的次数。若字符出现更多次,模式匹配将失败。
指定上下限间隔的示例如下:
$ echo "bt" | gawk --re-interval '/be{1,2}t/{print $0}'
$
$ echo "bet" | gawk --re-interval '/be{1,2}t/{print $0}'
bet
$ echo "beet" | gawk --re-interval '/be{1,2}t/{print $0}'
beet
$ echo "beeet" | gawk --re-interval '/be{1,2}t/{print $0}'
$
在此示例中,“e” 字符可以出现一次或两次,模式匹配才能通过;否则,模式匹配失败。
间隔模式匹配也适用于字符类。示例如下:
$ echo "bt" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
$
$ echo "bat" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bat
$ echo "bet" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
bet
$ echo "beat" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
beat
$ echo "beet" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
beet
$ echo "beeat" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
$
$ echo "baeet" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
$
$ echo "baeaet" | gawk --re-interval '/b[ae]{1,2}t/{print $0}'
$
若文本模式中恰好有一个或两个 “a” 或 “e” 字母的实例,此正则表达式模式匹配;但如果以任何组合出现更多实例,模式匹配将失败。
2.4 管道符号
管道符号允许指定两个或更多模式,正则表达式引擎在检查数据流时使用逻辑或公式。若任何模式与数据流文本匹配,文本通过;若没有模式匹配,数据流文本失败。
使用管道符号的格式如下:
expr1|expr2|...
示例如下:
$ echo "The cat is asleep" | gawk '/cat|dog/{print $0}'
The cat is asleep
$ echo "The dog is asleep" | gawk '/cat|dog/{print $0}'
The dog is asleep
$ echo "The sheep is asleep" | gawk '/cat|dog/{print $0}'
$
此示例在数据流中查找正则表达式 “cat” 或 “dog”。正则表达式和管道符号之间不能有任何空格,否则它们将被添加到正则表达式模式中。
管道符号两侧的正则表达式可以使用任何正则表达式模式(包括字符类)来定义文本。示例如下:
$ echo "He has a hat." | gawk '/[ch]at|dog/{print $0}'
He has a hat.
$
此示例将匹配数据流文本中的 “cat”、“hat” 或 “dog”。
2.5 分组表达式
可使用括号对正则表达式模式进行分组。当对正则表达式模式进行分组时,该组被视为一个标准字符,可将特殊字符应用于该组,就像应用于常规字符一样。示例如下:
$ echo "Sat" | gawk '/Sat(urday)?/{print $0}'
Sat
$ echo "Saturday" | gawk '/Sat(urday)?/{print $0}'
Saturday
$
将 “urday” 结尾分组并加上问号,允许模式匹配完整的日期名称 “Saturday” 或缩写名称 “Sat”。
通常将分组与管道符号一起使用,以创建可能的模式匹配组。示例如下:
$ echo "cat" | gawk '/(c|b)a(b|t)/{print $0}'
cat
$ echo "cab" | gawk '/(c|b)a(b|t)/{print $0}'
cab
$ echo "bat" | gawk '/(c|b)a(b|t)/{print $0}'
bat
$ echo "bab" | gawk '/(c|b)a(b|t)/{print $0}'
bab
$ echo "tab" | gawk '/(c|b)a(b|t)/{print $0}'
$
$ echo "tac" | gawk '/(c|b)a(b|t)/{print $0}'
$
模式
(c|b)a(b|t)
匹配第一组字母的任何组合以及第二组字母的任何组合。
3. 实际应用示例
3.1 统计目录文件
以下是一个统计
PATH
环境变量中定义的目录中可执行文件数量的 shell 脚本。操作步骤如下:
1. 解析
PATH
变量,将每个目录名分隔开。
PATH
变量中的每个目录由冒号分隔,使用
sed
和简单的正则表达式将每个冒号替换为空格。示例如下:
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
$ echo $PATH | sed 's/:/ /g'
/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /usr/games /usr/local/games
$
-
使用标准的
for语句遍历每个目录。 -
使用
ls命令列出每个目录中的每个文件,并使用另一个for语句遍历每个文件,为每个文件递增计数器。
最终的脚本如下:
$ cat countfiles
#!/bin/bash
# count number of files in your PATH
mypath=$(echo $PATH | sed 's/:/ /g')
count=0
for directory in $mypath
do
check=$(ls $directory)
for item in $check
do
count=$[ $count + 1 ]
done
echo "$directory - $count"
count=0
done
$ ./countfiles
/usr/local/sbin - 0
/usr/local/bin - 2
/usr/sbin - 213
/usr/bin - 1427
/sbin - 186
/bin - 152
/usr/games - 5
/usr/local/games - 0
$
3.2 验证电话号码
正则表达式常用于验证数据,以确保数据符合脚本的正确格式。常见的数据验证应用是检查电话号码。在美国,人们使用几种常见的方式显示电话号码:
- (123)456 - 7890
- (123) 456 - 7890
- 123 - 456 - 7890
- 123.456.7890
构建正则表达式时,最好从左侧开始,构建模式以匹配可能遇到的字符。具体步骤如下:
1. 电话号码中可能有左括号,可使用模式
^\(?
匹配。脱字符用于表示数据的开头,由于左括号是特殊字符,必须对其进行转义才能将其用作普通字符。问号表示左括号可能在数据中出现,也可能不出现以匹配。
2. 接下来是三位区号。在美国,区号以数字 2 开头(没有区号以数字 0 或 1 开头),可以到 9。使用模式
[2 - 9][0 - 9]{2}
匹配区号,这要求第一个字符是 2 到 9 之间的数字,后面跟着任意两个数字。
3. 区号后面的右括号可能出现,也可能不出现,使用模式
\)?
匹配。
4. 区号后面可以是空格、无空格、破折号或点,使用字符组和管道符号将它们组合起来,模式为
(| |-|\.)
。第一个管道符号紧跟左括号,用于匹配无空格的情况。必须对点进行转义,否则它将被解释为匹配任何字符。
5. 接下来是三位电话交换号码,使用模式
[0 - 9]{3}
匹配。
6. 电话交换号码后面必须匹配空格、破折号或点,使用模式
( |-|\.)
匹配。
7. 最后,匹配字符串末尾的四位本地电话分机号,使用模式
[0 - 9]{4}$
匹配。
将整个模式组合起来,得到:
^\(?[2 - 9][0 - 9]{2}\)?(| |-|\.)[0 - 9]{3}( |-|\.)[0 - 9]{4}$
可在
gawk
中使用此正则表达式模式过滤掉格式不正确的电话号码。创建一个简单的脚本,在
gawk
中使用该正则表达式,并将电话列表通过该脚本进行过滤。使用
gawk
中的正则表达式间隔时,必须使用
--re-interval
命令行选项,否则将无法获得正确的结果。
脚本如下:
$ cat isphone
#!/bin/bash
# script to filter out bad phone numbers
gawk --re-interval '/^\(?[2-9][0-9]{2}\)?(| |-|\.)
[0-9]{3}( |-|\.)[0-9]{4}/{print $0}'
$
综上所述,正则表达式在数据处理和验证方面具有强大的功能,通过合理运用各种正则表达式符号和模式,可以高效地完成各种复杂的任务。无论是处理拼写错误的单词、验证数据格式,还是统计文件数量,正则表达式都能发挥重要作用。
3.3 正则表达式在数据清洗中的应用
在实际的数据处理过程中,数据清洗是一个重要的环节,正则表达式在其中可以发挥巨大的作用。例如,我们有一个包含各种格式日期的数据文件,需要将其统一为特定的格式。
假设数据文件
dates.txt
内容如下:
2023-10-15
10/15/2023
15 Oct 2023
我们的目标是将所有日期统一转换为
YYYY-MM-DD
格式。以下是实现该功能的脚本:
#!/bin/bash
# 脚本用于将不同格式的日期统一转换为 YYYY-MM-DD 格式
while IFS= read -r line; do
# 匹配 YYYY-MM-DD 格式
if [[ $line =~ ^([0-9]{4})-([0-9]{2})-([0-9]{2})$ ]]; then
echo "$line"
# 匹配 MM/DD/YYYY 格式
elif [[ $line =~ ^([0-9]{2})/([0-9]{2})/([0-9]{4})$ ]]; then
echo "${BASH_REMATCH[3]}-${BASH_REMATCH[1]}-${BASH_REMATCH[2]}"
# 匹配 DD MMM YYYY 格式
elif [[ $line =~ ^([0-9]{2}) ([A-Za-z]{3}) ([0-9]{4})$ ]]; then
month=$(date -d "${BASH_REMATCH[2]} 1 ${BASH_REMATCH[3]}" +%m)
echo "${BASH_REMATCH[3]}-$month-${BASH_REMATCH[1]}"
fi
done < dates.txt
操作步骤如下:
1. 读取
dates.txt
文件的每一行。
2. 使用
[[ $line =~ regex ]]
来匹配不同格式的日期。
3. 对于不同格式的日期,使用
BASH_REMATCH
数组提取匹配的部分,并进行相应的转换。
4. 输出统一格式的日期。
3.4 正则表达式在日志分析中的应用
日志文件通常包含大量的信息,使用正则表达式可以快速筛选出我们需要的信息。例如,有一个 Web 服务器的访问日志文件
access.log
,我们想要统计特定 IP 地址的访问次数。
假设
access.log
文件内容如下:
192.168.1.100 - - [15/Oct/2023:10:30:00 +0800] "GET /index.html HTTP/1.1" 200 1234
192.168.1.101 - - [15/Oct/2023:10:31:00 +0800] "GET /about.html HTTP/1.1" 200 1122
192.168.1.100 - - [15/Oct/2023:10:32:00 +0800] "GET /contact.html HTTP/1.1" 200 1345
以下是统计特定 IP 地址访问次数的脚本:
#!/bin/bash
# 脚本用于统计特定 IP 地址的访问次数
target_ip="192.168.1.100"
count=$(grep -E "^$target_ip" access.log | wc -l)
echo "IP 地址 $target_ip 的访问次数为: $count"
操作步骤如下:
1. 定义目标 IP 地址
target_ip
。
2. 使用
grep -E "^$target_ip"
筛选出以目标 IP 地址开头的日志行。
3. 使用
wc -l
统计筛选出的日志行数量。
4. 输出统计结果。
3.5 正则表达式在文本替换中的应用
在文本处理中,经常需要对特定的文本进行替换。例如,将一段文本中的所有电子邮件地址替换为
[EMAIL]
。
假设文本文件
text.txt
内容如下:
联系我们:info@example.com 或 support@example.org
以下是实现文本替换的脚本:
#!/bin/bash
# 脚本用于将文本中的电子邮件地址替换为 [EMAIL]
sed -E 's/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/[EMAIL]/g' text.txt
操作步骤如下:
1. 使用
sed -E
启用扩展正则表达式。
2. 使用正则表达式
[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}
匹配电子邮件地址。
3. 使用
s/regex/replacement/g
命令将匹配到的电子邮件地址替换为
[EMAIL]
。
4. 输出替换后的文本。
4. 正则表达式的性能优化
4.1 避免不必要的回溯
回溯是正则表达式引擎在匹配过程中尝试不同路径的过程,过多的回溯会导致性能下降。例如,正则表达式
a*a
在匹配
aaaa
时会进行多次回溯。可以优化为
a+
来避免不必要的回溯。
4.2 使用非贪婪匹配
默认情况下,正则表达式使用贪婪匹配,即尽可能多地匹配字符。使用非贪婪匹配(在量词后加
?
)可以减少匹配的字符数量,提高性能。例如,
.*?
是非贪婪匹配,而
.*
是贪婪匹配。
4.3 合理使用字符类
字符类可以减少正则表达式的复杂度,提高匹配效率。例如,使用
[0-9]
代替
0|1|2|3|4|5|6|7|8|9
。
4.4 预编译正则表达式
在脚本中多次使用相同的正则表达式时,可以预编译正则表达式,避免重复编译带来的性能开销。例如,在 Python 中可以使用
re.compile()
函数预编译正则表达式。
5. 总结
正则表达式是一种强大的文本处理工具,在数据处理、验证、日志分析等领域都有广泛的应用。通过掌握正则表达式的基本语法和高级特性,如字符类、特殊字符、扩展符号等,可以编写出高效、准确的正则表达式模式。同时,在使用正则表达式时,要注意性能优化,避免不必要的回溯和复杂的模式。
以下是正则表达式常用符号总结表格:
| 符号 | 描述 |
| — | — |
|
^
| 匹配行的开头 |
|
$
| 匹配行的结尾 |
|
.
| 匹配任意单个字符 |
|
*
| 匹配前面的字符零次或多次 |
|
+
| 匹配前面的字符一次或多次 |
|
?
| 匹配前面的字符零次或一次 |
|
{m}
| 匹配前面的字符恰好
m
次 |
|
{m,n}
| 匹配前面的字符至少
m
次,最多
n
次 |
|
\|
| 逻辑或,匹配多个模式中的一个 |
|
()
| 分组,将多个字符作为一个整体处理 |
|
[]
| 字符类,匹配方括号内的任意一个字符 |
|
[^]
| 否定字符类,匹配不在方括号内的任意一个字符 |
通过不断练习和实践,相信你可以熟练掌握正则表达式的使用,解决各种复杂的文本处理问题。
mermaid 格式流程图:
graph TD;
A[开始] --> B[选择正则表达式应用场景];
B --> C{是否需要精确匹配};
C -- 是 --> D[使用精确匹配符号];
C -- 否 --> E[使用范围或字符类];
D --> F[检查是否需要特殊符号];
E --> F;
F -- 是 --> G[使用特殊符号如 * + ? 等];
F -- 否 --> H[构建基本正则表达式];
G --> I[测试正则表达式];
H --> I;
I -- 通过 --> J[应用正则表达式到实际场景];
I -- 不通过 --> K[调整正则表达式];
K --> I;
J --> L[结束];
希望本文能帮助你更好地理解和使用正则表达式,在实际应用中发挥其强大的功能。
超级会员免费看
36

被折叠的 条评论
为什么被折叠?



