正则表达式

正则表达式概述

正则表达式(Regular Expression,简称为RegExp或Regex)是一种用于匹配、搜索、替换文本的强大工具。它由一系列字符和特殊符号组成,可以描述字符串的模式,从而实现对字符串的复杂操作。正则表达式在编程和文本处理领域广泛应用,包括文本编辑器、编程语言、命令行工具等。

正则表达式和通配符的区别

正则表达式(Regular Expression)和通配符(Wildcard)都是用于字符串匹配和模式匹配的工具,但它们在语法和功能上有一些区别。

  1. 语法:

    • 正则表达式使用一系列的字符和特殊符号来构建匹配模式,可以更精确地描述字符串的模式。正则表达式提供了更丰富的语法,允许指定字符的数量、位置、逻辑关系等。
    • 通配符通常是单个字符的占位符。在大多数情况下,通配符使用特定字符(如*?)来表示模式,而不提供像正则表达式那样丰富的语法。
  2. 功能:

    • 正则表达式的功能更强大,可以实现复杂的模式匹配、替换、分组等操作。正则表达式支持范围、字符集、量词、分组、反向引用等高级功能,能够精确匹配多种模式。
    • 通配符的功能相对较简单。常见的通配符是*?*表示任意长度的字符序列(包括空字符串),?表示匹配任意一个字符。
  3. 应用范围:

    • 正则表达式广泛应用于文本处理、编程语言、命令行工具等领域,适用于需要进行复杂字符串匹配和处理的情况。
    • 通配符通常用于文件系统中的文件名匹配,例如在Linux中用于ls命令的文件名匹配,或在Windows中用于文件搜索。
  4. 例子:

    • 正则表达式示例:匹配邮箱地址 [\w\.-]+@[\w\.-]+,匹配日期 \d{4}-\d{2}-\d{2}
    • 通配符示例:在Linux中,*.txt匹配所有以.txt结尾的文件名;file?.txt匹配类似于file1.txtfileA.txt的文件名。

总的来说,正则表达式比通配符更灵活、功能更强大,但也更复杂。通配符则更适合简单的文件名匹配。根据具体的需求,选择适合的工具可以提高匹配效率和准确度。

基本正则表达式和扩展正则表达式有什么区别

基本正则表达式和扩展正则表达式最大的区别:基本正则需要加"\“转义符,扩展正则不需要加转义符

基本正则表达式(Basic Regular Expressions,BRE)和扩展正则表达式(Extended Regular Expressions,ERE)是两种不同的正则表达式语法,用于在不同的工具和环境中进行字符串匹配和处理。它们在语法和支持的功能上有一些区别。

基本正则表达式(BRE):

基本正则表达式是最早的正则表达式语法,最初由Unix的ed编辑器引入,然后扩展到其他Unix工具如grepsedawk中。BRE具有以下特点:

  1. 元字符功能受限: 基本正则表达式中的元字符(如*+?|等)的特殊功能在一些情况下需要使用反斜杠进行转义,才能实现其本身的含义。

  2. 不支持捕获分组: 基本正则表达式不支持捕获分组(使用括号进行分组),因此在匹配和提取文本时有限制。

扩展正则表达式(ERE):

扩展正则表达式是在基本正则表达式的基础上进行了扩展,它添加了更多的功能和语法,使得正则表达式更强大和易用。ERE最初由egrep命令引入,现在也广泛应用于许多工具和编程语言中。

  1. 元字符更直观: 在扩展正则表达式中,元字符的功能更直观,无需使用额外的转义字符。

  2. 支持捕获分组: 扩展正则表达式支持使用圆括号进行捕获分组,这样可以更方便地提取匹配的部分。

  3. 更多的量词和字符类: 扩展正则表达式支持更多种类的量词(如{n}{n,}{n,m})和字符类(如\d\w\s等)。

综上所述,扩展正则表达式相对于基本正则表达式来说,功能更强大且更易用,它是在许多现代工具和编程语言中广泛使用的标准正则表达式语法。在使用正则表达式时,要注意所使用的工具和环境,以确保选择适合的正则表达式语法。

元字符

代码 说明
. 匹配任意单个字符(除了换行符)
\d 匹配任意一个数字字符(相当于 [0-9]
\D 除了数字的其他字符(相当于 [^0-9]
\w 匹配任意一个字母、数字或下划线字符(相当于[a-Z0-9_],注意 Z 为大写)
\W 除了字母、数字、下划线、汉字的其他字符
\s 匹配任意一个空白字符(空格、制表符、换行等)。
\S 除了空白符 的其他字符
[] 匹配指定范围内的任意单个字符,例如 [a-z] 表示匹配任意一个小写字母。
[^] 匹配指定范围外的任意单个字符,例如 [^0-9] 表示匹配任意一个非数字字符。
[:alnum:] 所有字母和数字,即 A-Z、a-z、0-9
[:alpha:] 所有英文大小写字符,即 A-Z、a-z
[:lower:] 所有英文小写字母
[:upper:] 所有英文大写字母
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃…)
[:digit:] 十进制数字
[:xdigit:] 十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号

你的总结关于正则表达式中的元字符和一些预定义字符类是非常准确的,涵盖了许多常见的情况。这些元字符和字符类在正则表达式中用于匹配特定类型的字符,从而实现不同类型的字符串匹配。

对于预定义字符类,您的总结也是准确的,它们在正则表达式中用于匹配特定类别的字符,比如数字、字母、空白字符等。需要注意的是,不同的正则表达式引擎可能会略有差异,所以在具体使用时还是要查阅相关文档以确保一致性。

总体而言,您的总结已经很详细了,没有什么需要补充或纠错的地方。如果您想深入了解正则表达式的用法和各种元字符的行为,可以通过练习和实践来加深理解。

注意事项

[:alnum:] 所有字母和数字,即 A-Z、a-z、0-9 对吗?

几乎对,但是您的描述稍有不准确。[:alnum:] 是一个在一些正则表达式引擎中用于表示字母和数字字符类的特殊表示法。正确的表达是:[:alnum:] 匹配所有字母(A-Z、a-z)和数字(0-9),但不包括其他字符,如标点符号或空格。

在某些正则表达式引擎和工具中,您可以使用类似于 [[:alnum:]] 的表示法来匹配字母和数字字符类。但请注意,这种写法可能在不同的环境中有所不同,所以最好查看您所使用的工具的文档来了解确切的用法。

要匹配所有字母(A-Z、a-z)和数字(0-9),您可以使用 [A-Za-z0-9] 或简写成 \w(在支持扩展正则表达式语法的环境中)。

位置锚定

位置锚定可以用于定位出现的位置

代码 说明
^ 匹配字符串的开头。
$ 匹配字符串的结尾。
\<\b 词首锚定,用于单词模式的左侧
\>\b 词尾锚定,用于单词模式的右侧
\B 匹配不是单词开头或结束的位置

你的总结关于正则表达式中的位置锚定是基本准确的。这些位置锚定符号在正则表达式中用于指定匹配发生的位置,而不是实际的字符。下面我会对你提到的每个锚定符号进行一些补充:

  1. ^(开始锚定):这个符号匹配字符串的开头。在多行模式中(如果支持的话),它也可以匹配行的开头。例如,^apple会匹配以 “apple” 开头的字符串或行。

  2. $(结束锚定):这个符号匹配字符串的结尾。在多行模式中,它也可以匹配行的结尾。例如,apple$会匹配以 “apple” 结尾的字符串或行。

  3. \<\b(词首锚定):这些符号用于匹配单词的开头。\b 通常在单词字符和非单词字符之间的位置匹配,以确保匹配的是单词的真正开头。例如,\bapple会匹配以 “apple” 开头的单词。

  4. \>\b(词尾锚定):这些符号用于匹配单词的结尾。\b 通常在单词字符和非单词字符之间的位置匹配,以确保匹配的是单词的真正结尾。例如,apple\b会匹配以 “apple” 结尾的单词。

  5. \B(反词边界锚定):这个符号匹配不是单词开头或结束的位置。它在单词字符之间的位置匹配,以确保匹配的不是单词的边界。例如,\Bapple\B会匹配包含 “apple” 的单词内部。

这些位置锚定在正则表达式中常用于限制匹配发生的位置,从而实现更精确的匹配。根据正则表达式引擎的不同,这些锚定符号的行为可能会稍有不同,因此在使用时最好查阅相关文档以确保正确的使用。

范例

^PATTERN$ # 匹配模式整行

^$ # 匹配空行

^[[:space:]]*$ # 匹配空白行

\<PATTERN\> # 匹配整个单词

匹配次数

用在要指定次数的字符后面,用于指定前面的字符要出现的次数

代码 说明
* 匹配前面字符任意次,包括0次(贪婪模式,尽可能长的匹配)
? 匹配前面字符0或1次(可有可无)
+ 匹配前面字符1次或多次(至少一次或以上,>=1)
{n} 匹配前面字符n次
{m,n} 匹配前面字符至少m次,最多n次
{,n} 匹配前面字符最多n次(<=n)
{n,} 匹配前面字符至少n次(>=n)({1,} 相当于 +

你的总结关于正则表达式中匹配次数的部分是准确的,描述了一些常用的量词。这些量词在正则表达式中用于指定匹配的次数,从而实现不同程度的匹配灵活性。下面我会对你提到的每个量词进行一些补充:

  1. *(零次或多次):这个量词匹配前面的字符零次或多次。这是贪婪模式,会尽可能多地匹配字符。例如,ab*c会匹配 “ac”、“abc”、“abbc” 等。

  2. ?(零次或一次):这个量词匹配前面的字符零次或一次,表示可有可无。例如,colou?r会匹配 “color” 和 “colour”。

  3. +(一次或多次):这个量词匹配前面的字符至少一次。例如,go+l会匹配 “gol”、“gool”、“goooool” 等。

  4. {n}(恰好n次):这个量词匹配前面的字符恰好出现 n 次。例如,a{3}会匹配 “aaa”。

  5. {m,n}(至少m次,最多n次):这个量词匹配前面的字符出现至少 m 次,最多 n 次。例如,a{2,4}会匹配 “aa”、“aaa” 和 “aaaa”。

  6. {,n}(最多n次):这个量词匹配前面的字符最多出现 n 次(包括零次)。例如,b{,3}会匹配空字符串、“b”、“bb” 和 “bbb”。

  7. {n,}(至少n次):这个量词匹配前面的字符至少出现 n 次。例如,c{2,}会匹配 “cc”、“ccc”、“cccc” 等。

你的总结涵盖了一些常见的量词,这些量词可以帮助你调整正则表达式的匹配模式,以适应不同的需求。如果在使用量词时遇到问题,可以通过实际测试和文档查阅来更好地理解其行为。

分组和捕获

代码 说明
(pattern) 分组,分组后的内容会被视为一个整体来进行处理。首个分组会从1开始编号,可以使用\数字引用指定的分组。
\数字 引用分组(后向引用),分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为: \1, \2, \3, … \1 表示引用第一个捕获分组的内容,\2 表示引用第二个捕获分组的内容,以此类推。后向引用允许在正则表达式中引用之前捕获的分组。这对于查找重复的模式或验证重复字符串非常有用。
(?<name>pattern)(?'name'pattern) 为分组命名,而不使用默认的 \数字 这种命名方式。注意,Python 语法必须是 (?P<name>pattern)
(?:pattern) 忽略分组,即不会被 \数字 所捕获

范例

(ab)+ # 匹配 "ab" 出现一次或多次。


a|b         # a或b
C|cat       # C或cat
(C|c)at     # Cat或cat
## \1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
\(string1\(string2\)\)
\1 :string1\(string2\)
\2 :string2

在正则表达式中,\1 表示引用正则表达式中的第一个捕获分组所匹配的内容。这是一个用于后向引用的特殊语法。如果您在正则表达式中使用了圆括号 () 来创建捕获分组,那么这些分组可以在表达式中的后续部分进行引用。\1 表示引用第一个捕获分组,\2 表示引用第二个捕获分组,以此类推。

让我以您提供的示例来解释一下:

假设您有一个字符串:\(string1\(string2\)\),这里有两对括号,您可以使用正则表达式来匹配这个字符串,并使用捕获分组来获取括号中的内容。

  • \(\) 是匹配左括号和右括号的特殊字符。
  • (string1\(string2\)) 是一个捕获分组,它匹配整个字符串 string1\(string2\)

如果您想要分别匹配和捕获两对括号中的内容,可以使用以下表达式:

  1. 对于第一个括号内的内容,\1 表示引用第一个捕获分组的内容,即 string1\(string2\)
  2. 如果在捕获分组 (string1\(string2\)) 中再有一个捕获分组,例如:(string1(\(string2\))),那么 \2 会引用第二个捕获分组,即 \(string2\)

所以,#\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符,即 string1\(string2\)。同样,\2 表示匹配到的第二个捕获分组的内容,即 string2

请注意,后向引用的使用可能会因正则表达式引擎而有所不同,所以确保在您使用的特定环境中测试和验证。

(?<name>pattern)

命名捕获组允许你给一个特定的捕获组指定一个名称,以便在匹配成功后可以通过名称来引用捕获的内容。

下面是一个使用命名捕获组的示例,假设你想从日期字符串中提取年份,但是你想用名为 “year” 的捕获组来表示这个年份:

正则表达式:(?<year>\d{4})-\d{2}-\d{2}

在这个正则表达式中,(?<year>\d{4}) 是一个命名捕获组,它用来捕获四位数字作为年份。\d{4} 匹配四个数字,表示年份的部分。你可以在匹配成功后使用 “year” 这个名称来引用捕获的年份内容。

虽然命名捕获组不会忽略匹配的部分,但它们允许你更方便地引用和处理捕获的内容。如果你想要完全忽略某些部分,仍然可以使用非捕获分组 (?: ... )

(?:pattern)

在正则表达式中,你可以使用非捕获分组来忽略匹配的部分,从而不会把这些部分放入结果中的捕获组。非捕获分组使用语法 (?: ... ) 来表示,它和普通的捕获分组 ( ... ) 类似,但不会将匹配的内容保存在分组中。这对于你想要匹配但不关心捕获的内容非常有用。

以下是一个示例,假设你想要匹配一个时间字符串,但只关心小时部分,不关心分钟和秒:

正则表达式:(?:\d{2}):(?:\d{2}):(?:\d{2})

在这个正则表达式中,(?:\d{2}) 表示一个非捕获的两位数字的分组,用来匹配小时部分。你可以在这个正则表达式中添加更多的非捕获分组来匹配其他部分,比如分钟和秒,但是不会把它们放入捕获组。

使用非捕获分组可以让你更精确地控制哪些部分需要捕获,哪些部分只需要匹配而不保存。

当然!以下是一个简单的例子,假设你有一个文本,里面包含了一些邮箱地址,但你只关心域名部分而不关心用户名:

文本:

JohnDoe@example.com
JaneSmith@gmail.com
Alice123@yahoo.com

你可以使用正则表达式来匹配域名部分,同时忽略用户名部分,如下所示:

正则表达式:(?:\w+)@(\w+\.\w+)

在这个正则表达式中,(?:\w+) 匹配用户名(但不捕获),@ 匹配邮箱地址中的 “@” 符号,而 (\w+\.\w+) 捕获了域名部分。由于我们只关心域名部分,所以我们只将域名部分放入了捕获组中。

使用这个正则表达式,你可以找到文本中的域名部分,而不需要捕获和处理用户名部分。

断言

在正则表达式中,断言是一种特殊的模式匹配,用于指定位置,而不是实际的字符。它允许你在进行匹配时指定条件,而不消耗实际的文本字符。断言通常用于查找特定位置之前或之后的模式。以下是一些常见的断言及其说明:

  1. 正向肯定断言 (?=pattern): 正向肯定断言用于指定一个位置,该位置之后的字符必须与给定的模式相匹配。但是,匹配的字符不会被包含在最终的匹配结果中。

    示例:(?=abc) 会匹配在其后紧跟着 “abc” 的位置,但不会消耗实际的字符。

  2. 正向否定断言 (?!=pattern): 正向否定断言用于指定一个位置,该位置之后的字符必须与给定的模式匹配。同样,匹配的字符不会被包含在最终的匹配结果中。

    示例:(?!=xyz) 会匹配在其后不紧跟着 “xyz” 的位置。

  3. 反向肯定断言 (?<=pattern): 反向肯定断言用于指定一个位置,该位置之前的字符必须与给定的模式相匹配。同样,匹配的字符不会被包含在最终的匹配结果中。

    示例:(?<=start) 会匹配在其前紧跟着 “start” 的位置。

  4. 反向否定断言 (?<!pattern): 反向否定断言用于指定一个位置,该位置之前的字符必须与给定的模式匹配。同样,匹配的字符不会被包含在最终的匹配结果中。

    示例:(?<!end) 会匹配在其前不紧跟着 “end” 的位置。

这些断言可以在正则表达式中的特定位置使用,以便更精确地指定模式的匹配条件,而不会实际匹配或消耗字符。在这些断言中,你可以使用普通的正则表达式模式,以及之前提到的分组和后向引用来构建更复杂的匹配条件。注意,不同的编程语言可能对断言的语法支持有所不同,因此在使用时需要查阅相关文档。

(?<=pattern)

## lscpu | grep -P "(?<=^CPU\(s\):)\s+(\d+)$"
CPU(s):                             4

1

这个正则表达式用于匹配类似于 “CPU(s): 2” 的字符串,其中 “CPU(s)” 是固定的前缀,后面跟着一个或多个空白字符,然后是一个数字。

它由以下部分组成:

(?<=^CPU(s):) 这是一个前瞻断言,它检查字符串的开头是否是 “CPU(s):"。这个前瞻断言使用了零宽度断言,意味着它不会匹配任何字符,而只是检查它的左侧是否符合预期的模式。 \s+ 这个部分匹配一个或多个空白字符,例如空格、制表符或换行符。 (\d+) 这个部分匹配一个数字,它被捕获在一个捕获组中,可以在后面的代码中使用。 )$ 这个部分用于标记字符串的结尾,它与开头的前瞻断言相呼应。

整个表达式组合在一起,可以检查一个字符串是否符合 “CPU(s): <数字>” 的格式。

2

在这个正则表达式中,有两个断言部分:

(?<=^CPU(s):)\s+ - 这个部分用于匹配 “CPU(s): " 后面跟着的一个或多个空格。它使用了一个正向预查功能,即 “?<=”, 它告诉正则表达式引擎在找到一个匹配项之前,先检查它的左边是否匹配 “CPU(s): “。这个断言部分确保了我们只匹配跟在 “CPU(s): " 后面的空格,而不是其他地方的空格。

(\d+) - 这个部分用于匹配一个或多个数字。它使用了一个捕获组,即括号中的部分,它可以将匹配到的数字捕获并存储在一个变量中,以便我们在代码中使用。

总的来说,这个正则表达式使用了两个断言部分来确保我们只匹配跟在 “CPU(s): " 后面的一个或多个空格,以及一个或多个数字,并将这个数字提取出来。

逻辑运算符与转义

代码 说明
` `
\ 用于转义特殊字符,例如 \\ 表示匹配一个反斜杠。

其他

贪婪与非贪婪模式

在正则表达式中,贪婪(greedy)和非贪婪(non-greedy)模式是用来描述匹配规则的两种不同方式。它们决定了在匹配字符串时正则表达式引擎如何选择匹配的文本。

  1. 贪婪模式(Greedy mode): 贪婪模式是默认的模式,它会尽可能多地匹配符合条件的文本。例如,给定正则表达式 a.*b 和字符串 axxxxxb,贪婪模式会匹配整个字符串,而不仅仅是 axb 部分。在贪婪模式下,. 表示匹配任意字符,* 表示前一个字符可以重复任意次数(包括零次)。

  2. 非贪婪模式(Non-greedy mode,也叫做懒惰模式或最小匹配模式): 非贪婪模式则是在贪婪模式的量词后面加上 ?,例如 a.*?b。这种模式会尽可能少地匹配符合条件的文本。使用上述正则表达式和字符串 axxxxxb,非贪婪模式只会匹配 axb 部分,而不会一直匹配到最后。.*? 表示匹配任意字符任意次数,但尽可能少地匹配。

在正则表达式中,使用非贪婪模式可以避免匹配过多的文本,特别是在使用像 .* 这样可以匹配大量字符的量词时。通过将量词后面的 ? 加入,可以使匹配尽可能地短,只匹配满足条件的最小文本片段。

综上所述,贪婪模式会尽可能多地匹配,而非贪婪模式会尽可能少地匹配。在编写正则表达式时,根据实际情况选择合适的模式可以确保你得到期望的匹配结果。

范例

让我们通过一个具体的例子来说明贪婪和非贪婪模式之间的差异。

考虑以下字符串:<p>Hello</p><p>World</p>

我们想要使用正则表达式从中匹配出两个<p>标签之间的内容。我们可以使用贪婪模式和非贪婪模式来看看它们的行为差异。

  1. 贪婪模式: 使用贪婪模式的正则表达式:<p>.*</p> 在这个表达式中,.* 表示匹配任意字符(除了换行符)任意次数,尽可能多地匹配。

贪婪模式匹配结果:<p>Hello</p><p>World</p> 它会从第一个<p>开始,一直匹配到最后一个</p>,将整个字符串作为一个匹配结果。

  1. 非贪婪模式: 使用非贪婪模式的正则表达式:<p>.*?</p> 在这个表达式中,.*? 表示匹配任意字符任意次数,但尽可能少地匹配。

非贪婪模式匹配结果:<p>Hello</p><p>World</p> 它会从第一个<p>开始,尽可能少地匹配,所以会匹配到两个<p>标签之间的内容分别作为两个独立的匹配结果。

通过这个例子,你可以看到贪婪模式和非贪婪模式的差异。贪婪模式尽可能多地匹配,而非贪婪模式尽可能少地匹配,这在特定情况下可以帮助我们更精准地提取我们所需的文本。

单行与多行模式

在正则表达式中,单行模式(也称为单行匹配模式)和多行模式是两种不同的模式,用于影响正则表达式如何匹配文本。它们与贪婪和非贪婪模式无关,而是关注正则表达式如何处理换行符和文本中的行。

  1. 单行模式(Single-line mode 或 Dot-all mode): 在单行模式下,正则表达式中的点 . 将匹配任意字符,包括换行符 \n。在默认情况下,点 . 匹配除了换行符外的所有字符。但在单行模式下,点 . 也可以匹配换行符。

你可以使用 (?s)(?dotall) 来启用单行模式。例如,正则表达式 (?s)abc. 将会匹配以 “abc” 开头,然后紧接着任意字符(包括换行符)的情况。

  1. 多行模式(Multi-line mode): 在多行模式下,正则表达式中的锚点 ^$ 将分别匹配行的开头和结尾,而不仅仅是整个字符串的开头和结尾。这对于处理文本中的多行数据非常有用。

你可以使用 (?m)(?multiline) 来启用多行模式。例如,正则表达式 (?m)^abc 将会匹配每一行的开头处的 “abc”。

引擎选项

在正则表达式中,引擎选项(或模式修饰符)是一些标记,可以在正则表达式中使用以改变匹配的行为。这些选项可以影响如何解释和匹配模式。不同的编程语言和正则表达式库可能使用不同的语法来表示引擎选项。

下面是一些常见的引擎选项及其含义:

代码 说明 Python
IgnoreCase 匹配时忽略大小写,这个选项使得正则表达式匹配时不区分字符的大小写。通常使用 i 标志表示,比如 /pattern/i re.l 或 re.IGNORECASE
Singleline 单行模式,这个选项使得 . 匹配任何字符,包括换行符。通常使用 s 标志表示,比如 /(?s)pattern/ re.s 或 re.DOTALL
Multiline 多行模式,这个选项影响 ^$ 锚点的行为,使它们匹配每行的开头和结尾,而不仅仅是整个字符串的开头和结尾。通常使用 m 标志表示,比如 /^pattern/m re.M 或 re.MULTILINE

单行多行模式总结:

  • 默认模式:将整个测试字符串看作一个一行的大字符串(. 不可以匹配 \n);
  • 单行模式:将整个测试字符串看作一个一行的大字符串(. 可以匹配 \n);
  • 多行模式:可以把一行大字符串用 \n 分割成多行,^ 指的是行首,$ 行尾(每个换行符 \n 前面的为行尾,后面的为行首)

注意:如果遇到以\r\n结尾的字符串

处理以\r\n结尾的字符串时,通常涉及到处理换行符和行尾的情况。\r\n表示回车换行,是一种在Windows操作系统中常见的换行表示方式。以下是一些处理这种情况的方法:

  1. 去除行尾的\r\n: 如果你想要从字符串末尾去除\r\n,可以使用字符串处理函数来完成。不同的编程语言可能有不同的函数,但通常是类似 trim()rstrip() 这样的函数。这些函数会去除字符串末尾的空格、制表符和换行符等。

  2. 分割行: 如果你想要分割以\r\n结尾的字符串为多行,可以使用适当的字符串分割函数,将字符串分割成行的数组或列表。在大多数编程语言中,使用 split() 函数可以根据换行符进行分割。

  3. 正则表达式处理: 如果你需要更复杂的处理,比如匹配特定模式的行,可以使用正则表达式来分割或处理字符串。例如,使用正则表达式 /.*\r\n/ 可以匹配以\r\n结尾的行,然后你可以对匹配到的行进行进一步处理。

以下是一些使用Python的示例代码,展示如何处理以\r\n结尾的字符串:

## 去除行尾的`\r\n`
text = "This is a line.\r\n"
cleaned_text = text.rstrip("\r\n")
print(cleaned_text)

## 分割行
multiline_text = "Line 1\r\nLine 2\r\nLine 3\r\n"
lines = multiline_text.split("\r\n")
print(lines)

## 使用正则表达式匹配以`\r\n`结尾的行
import re
multiline_text = "Line 1\r\nLine 2\r\nLine 3\r\n"
pattern = r".*\r\n"
matches = re.findall(pattern, multiline_text)
for match in matches:
    print(match.strip())  # 去除行尾的换行符

无论使用哪种方法,目标都是根据实际需要来处理以\r\n结尾的字符串,确保在你的应用中得到正确的行为。

其他非常用选项:

  1. 全局匹配(Global):这个选项使得正则表达式匹配所有出现的情况,而不仅仅是第一个。通常使用 g 标志表示,比如 /pattern/g

  2. 只匹配一次(Only once 或 Sticky):这个选项使得正则表达式只匹配目标字符串的当前位置之后的文本。通常使用 y 标志表示,比如 /(?y)pattern/

  3. 忽略空白(Ignore whitespace 或 Extended):这个选项忽略正则表达式中的空格和注释,可以更容易阅读复杂的模式。通常使用 x 标志表示,比如 /pattern/x

  4. Unicode 模式(Unicode):这个选项使得正则表达式中的一些元字符和量词对 Unicode 字符集进行操作。通常使用 u 标志表示,比如 /pattern/u

这些选项可以单独使用,也可以组合在一起。具体的语法可能因不同的编程语言和正则表达式库而有所不同。在使用正则表达式时,了解和理解这些选项的含义和用法是非常重要的,因为它们可以影响匹配的结果。

范例

举个例子来说明这两种模式的作用:

假设我们有以下文本:

abc
def
ghi

使用正则表达式 (?s)^d. 在单行模式下会匹配到 “def”,因为单行模式下 . 会匹配换行符。而使用正则表达式 (?m)^d. 在多行模式下,会匹配每一行的开头处的 “d”。

综上所述,单行模式和多行模式允许你在正则表达式中更好地处理包含换行符的文本以及多行数据。根据需要,你可以选择启用其中一个或同时启用它们。

范例

## 匹配 ipv4 地址(非精准)
\w+\.\w+\.\w+\.\w+


## 匹配 ipv4 地址(精准)
\b(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b


## 匹配 ipv6 地址
\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b



## 匹配邮箱地址
[\w\.-]+@[\w\.-]+


## 匹配手机号码
1\d{10}


## 匹配日期
\d{4}-\d{2}-\d{2}


## 匹配HTML标签
<[^>]+>


## 替换文本中的空格为下划线
s/\s+/_/g

排除掉空行和#开头的行

grep -v '^$' /etc/profile|grep -v '^#'

显示/proc/meminfo文件中以大小s开头的行(要求:使用两种方法)

#方法一
grep '^\(S\|s\)' /proc/meminfo
#方法二
grep -i '^s' /proc/meminfo 

显示/etc/passwd文件中不以/bin/bash结尾的行

grep -v '.*/bin/bash$' /etc/passwd

显示用户sync默认的shell程序

#grep取法
grep '^sync.*$' /etc/passwd | cut -d: -f7
#sed取法
sed -n '/^sync.*/s#.*:\(.*\)$#\1#p' /etc/passwd #基本正则写法
sed -En '/^sync.*/s#.*:(.*)$#\1#p' /etc/passwd #扩展正则写法

找出/etc/passwd中的两位或三位数

#grep取法
grep -Eo '\b[0-9]{2,3}\b' /etc/passwd
或者
grep -Eo '\<[0-9]{2,3}\>' /etc/passwd
#sed取法

显示etc/grub2.cfg文件中,至少以一个空白字符开头的且后面有非空白字符的行

grep  '^[[:space:]]\+[^[:space:]].\+$' /etc/grub2.cfg #基本正则
grep -E '^[[:space:]]+[^[:space:]].+$' /etc/grub2.cfg #扩展正则

找出“netstat -tan”命令结果中以LISTEN后跟任意多个空白字符结尾的行

显示CentOS7上所有UID小于1000以内的用户名和UID

添加用户bash、testbash、basher、sh、nologin(其shell为/sbin/nologin),找出/etc/passwd用户

名和shell同名的行

利用df和grep,取出磁盘各分区利用率,并从大到小排序

扩展的正则表达式表达IP地址

grep -Eo "^(([0-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$"

显示三个用户root、mage、wang的UID和默认shell

找出/etc/rc.d/init.d/functions文件中行首为某单词(包括下划线)后面跟一个小括号的行

使用egrep取出/etc/rc.d/init.d/functions中其基名

使用egrep取出上面路径的目录名

统计last命令中以root登录的每个主机IP地址登录次数

利用扩展正则表达式分别表示0-9、10-99、100-199、200-249、250-255

显示ifconfifig命令结果中所有IPv4地址

将此字符串:welcome to magedu linux 中的每个字符去重并排序,重复次数多的排到前面

扩展的正则表达式表达IP地址

grep -Eo "^(([0-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]?[0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$"