正则表达式

注:原文来自百度词条,此仅为阅读笔记。
 

一:正则表达式基础

  一个正则表达式,就是用某种模式去匹配一类字符串的一个公式。
  正则表达式由一些普通字符和一些元字符( metacharacters )组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义。
  元字符 描述
   .
  匹配任何单个字符。例如正则表达式 r.t 匹配这些字符串: rat rut r t ,但是不匹配 root
   $
  匹配行结束符。例如正则表达式 weasel$ 能够匹配字符串 "He's a weasel" 的末尾,但是不能匹配字符串 "They are a bunch of weasels."
   ^
  匹配一行的开始。例如正则表达式 ^When in 能够匹配字符串 "When in the course of human events" 的开始,但是不能匹配 "What and When in the"
   *
  匹配 0 或多个正好在它之前的那个字符。例如正则表达式 .* 意味着能够匹配任意数量的任何字符, (. 表示任何单个字符, .* 表示任意多个任意单个字符 )
   \
  这是引用符,用来将这里列出的这些元字符当作普通的字符来进行匹配。例如正则表达式 \$ 被用来匹配美元符号,而不是行尾,类似的,正则表达式 \. 用来匹配点字符,而不是任何字符的通配符。
   [ ]
   [c1-c2]
   [^c1-c2]
  匹配括号中的任何一个字符。例如正则表达式 r[aou]t 匹配 rat rot rut ,但是不匹配 ret 。可以在括号中使用连字符 - 来指定字符的区间,例如正则表达式 [0-9] 可以匹配任何数字字符;还可以制定多个区间,例如正则表达式 [A-Za-z] 可以匹配任何大小写字母。另一个重要的用法是“排除”,要想匹配除了指定区间之外的字符――也就是所谓的补集――在左边的括号和第一个字符之间使用 ^ 字符,例如正则表达式 [^269A-Z] 将匹配除了 2 6 9 和所有大写字母之外的任何字符。
   \< \>
  匹配词( word )的开始( \< )和结束( \> )。例如正则表达式 \<the 能够匹配字符串 "for the wise" 中的 "the" ,但是不能匹配字符串 "otherwise" 中的 "the" 。注意:这个元字符不是所有的软件都支持的 vim grep 都支持,注意: grep 使用时,要用双引号把字串括起来,比如: grep “\<HHG” a.file
   \( \)
  将 \( \) 之间的表达式定义为“组”( group ),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存 9 个),它们可以用 的符号来引用。 ( 见下面例子:简单例子最后一个了解其使用 )
   |
  将两个匹配条件进行逻辑“或”( Or )运算。例如正则表达式 (him|her) 匹配 "it belongs to him" "it belongs to her" ,但是不能匹配 "it belongs to them." 。注意:这个元字符不是所有的软件都支持的。 (vim 好像不支持, grep 需要用 option �CE (extend regular expression))
   +
  匹配 1 或多个正好在它之前的那个字符。例如正则表达式 9+ 匹配 9 99 999 98 93dsf 9..... 等。注意:这个元字符不是所有的软件都支持的。 (vim 好像不支持, grep 需要用 option �CE ,或者直接用 egrep)
   ?
  匹配 0 1 个正好在它之前的那个字符。注意:这个元字符不是所有的软件都支持的。 (egrep 支持 )
   \{i\}
   \{i,j\}
  匹配指定数目的字符,这些字符是在它之前的表达式定义的。例如正则表达式 A[0-9]\{3\} 能够匹配字符 "A" 后面跟着正好 3 个数字字符的串,例如 A123 A348 等,但是不匹配 A1234 。而正则表达式 [0-9]\{4,6\} 匹配连续的任意 4 个、 5 个或者 6 个数字字符。注意:这个元字符不是所有的软件都支持的。 (egrep 支持 )
想匹配所有 100 1000 的实例而排除 10 10000 ,可以使用: 10\{2,3\} ,这个正则表达式匹配数字 1 后面跟着 2 或者 3 0 的模式。在这个元字符的使用中一个有用的变化是忽略第二个数字,例如正则表达式 0\{3,\} 将匹配至少 3 个连续的 0
 
 

二:例子

  简单的例子

   :%s/ */ /g 把一个或者多个空格替换为一个空格。 ( 严格的描述: :%s/ 两个空格 */ 空格 /g, 如果 %s/ 后面是一个空格,出现的状况是所有字符之间出现空格,请理解 * 的真实含义 )
   :%s/ *$// 去掉行尾的所有空格。
   :%s/^/ / 在每一行头上加入一个空格。
   :%s/^[0-9][0-9]* // 去掉行首的所有数字字符。
   :%s/b[aeio]g/bug/g 将所有的 bag beg big bog 改为 bug
:%s/t\([aou]\)g/h$t/g 将所有 tag tog tug 分别改为 hat hot hug (注意用 group 的用法和使用引用前面被匹配的字符)。
 

  中级的例子(神奇的咒语)

  例 1
  将所有方法 foo(a,b,c) 的实例改为 foo(b,a,c) 。这里 a b c 可以是任何提供给方法 foo() 的参数。也就是说我们要实现这样的转换:
  之前 之后
   foo(10,7,2) foo(7,10,2)
   foo(x+13,y-2,10) foo(y-2,x+13,10)
   foo( bar(8), x+y+z, 5) foo( x+y+z, bar(8), 5)
  下面这条替换命令能够实现这一魔法:
   :%s/foo(\([^,]*\),\([^,]*\),\([^)]*\))/foo($2,$1,$3)/g
  现在让我们把它打散来加以分析。写出这个表达式的基本思路是找出 foo() 和它的括号中的三个参数的位置。第一个参数是用这个表达式来识别的:: \([^,]*\) ,我们可以从里向外来分析它:
   [^,] 除了逗号之外的任何字符
   [^,]* 0 或者多个非逗号字符
   \([^,]*\) 将这些非逗号字符标记为,这样可以在之后的替换模式表达式中引用它
   \([^,]*\), 我们必须找到 0 或者多个非逗号字符后面跟着一个逗号,并且非逗号字符那部分要标记出来以备后用。
  现在正是指出一个使用正则表达式常见错误的最佳时机。为什么我们要使用 [^,]* 这样的一个表达式,而不是更加简单直接的写法,例如: .* ,来匹配第一个参数呢?设想我们使用模式 .* 来匹配字符串 "10,7,2" ,它应该匹配 "10," 还是 "10,7," ?为了解决这个两义性( ambiguity ),正则表达式规定一律按照最长的串来,在上面的例子中就是 "10,7," ,显然这样就找出了两个参数而不是我们期望的一个。所以,我们要使用 [^,]* 来强制取出第一个逗号之前的部分。
这个表达式我们已经分析到了: foo(\([^,]*\) ,这一段可以简单的翻译为“当你找到 foo( 就把其后直到第一个逗号之前的部分标记为”。然后我们使用同样的办法标记第二个参数为。对第三个参数的标记方法也是一样,只是我们要搜索所有的字符直到右括号。我们并没有必要去搜索第三个参数,因为我们不需要调整它的位置,但是这样的模式能够保证我们只去替换那些有三个参数的 foo() 方法调用,在 foo() 是一个重载( overoading )方法时这种明确的模式往往是比较保险的。然后,在替换部分,我们找到 foo() 的对应实例,然后利用标记好的部分进行替换,是的第一和第二个参数交换位置。
 
  例 2
  假设有一个 CSV comma separated value )文件,里面有一些我们需要的信息,但是格式却有问题,目前数据的列顺序是:姓名,公司名,州名缩写,邮政编码,现在我们希望将这些数据重新组织,以便在我们的某个软件中使用,需要的格式为:姓名,州名缩写 - 邮政编码,公司名。也就是说,我们要调整列顺序,还要合并两个列来构成一个新列。另外,我们的软件不能接受逗号前后面有任何空格(包括空格和制表符)所以我们还必须要去掉逗号前后的所有空格。
  这里有几行我们现在的数据:
   Bill Jones, HI-TEK Corporation , CA, 95011
   Sharon Lee Smith, Design Works Incorporated, CA, 95012
   B. Amos , Hill Street Cafe , CA , 95013
   Alexander Weatherworth, The Crafts Store , CA , 95014
   ...
  我们希望把它变成这个样子:
   Bill Jones , CA 95011 ,HI-TEK Corporation
   Sharon Lee Smith , CA 95012 ,Design Works Incorporated
   B. Amos , CA 95013 , Hill Street Cafe
   Alexander Weatherworth , CA 95014 ,The Crafts Store
   ...
  我们将用两个正则表达式来解决这个问题。第一个移动列和合并列,第二个用来去掉空格。
  下面就是第一个替换命令:
   :%s/\([^,]*\),\([^,]*\),\([^,]*\),\(.*\)/$1,$3 $4 ,$2/
  这里的方法跟例 1 基本一样,第一个列(姓名)用这个表达式来匹配: \([^,]*\) ,即第一个逗号之前的所有字符,而姓名内容被用标记下来。公司名和州名缩写字段用同样的方法标记为和,而最后一个字段用 \(.*\) 来匹配( " 匹配所有字符直到行末 " )。替换部分则引用上面标记的那些内容来进行构造。
  第二个命令去掉逗号前后的所有空格:
   :%s/[ \t]*,[ \t]*/,/g
我们还是分解来看: [ \t] 匹配空格 / 制表符, [ \t]* 匹配 0 或多个空格 / 制表符, [ \t]*, 匹配 0 或多个空格 / 制表符后面再加一个逗号,最后, [ \t]*,[ \t]* 匹配 0 或多个空格 / 制表符接着一个逗号再接着 0 或多个空格 / 制表符。在替换部分,我们简单的我们找到的所有东西替换成一个逗号。这里我们使用了结尾的可选的 g 参数,这表示在每行中对所有匹配的串执行替换(而不是缺省的只替换第一个匹配串)。
 
  例 3
  假设有一个多字符的片断重复出现,例如:
   Billy tried really hard
   Sally tried really really hard
   Timmy tried really really really hard
   Johnny tried really really really really hard
  而你想把 "really" "really really" ,以及任意数量连续出现的 "really" 字符串换成一个简单的 "very" simple is good! ),那么以下命令:
   :%s/\(really \)\(really \)*/very /
  就会把上述的文本变成:
   Billy tried very hard
   Sally tried very hard
   Timmy tried very hard
   Johnny tried very hard
表达式 \(really \)* 匹配 0 或多个连续的 "really " (注意结尾有个空格),而 \(really \)\(really \)* 匹配 1 个或多个连续的 "really " 实例。
 

  困难的例子(不可思议的象形文字)

   Coming soon.
  不同工具中的正则表达式
   OK ,你已经准备使用 RE regular expressions ,正则表达式),但是你并准备使用 vi 。所以,在这里我们给出一些在其他工具中使用 RE 的例子。另外,我还会总结一下你在不同程序之间使用 RE 可能发现的区别。
当然,你也可以在 Visual C++ 编辑器中使用 RE 。选择 Edit->Replace ,然后选择 "Regular expression" 选择框, Find What 输入框对应上面介绍的 vi 命令 :%s/pat1/pat2/g 中的 pat1 部分,而 Replace 输入框对应 pat2 部分。但是,为了得到 vi 的执行范围和 g 选项,你要使用 Replace All 或者适当的手工 Find Next and Replace (译者按:知道为啥有人骂微软弱智了吧,虽然 VC 中可以选中一个范围的文本,然后在其中执行替换,但是总之不够 vi 那么灵活和典雅)。
 

  Sed将来再学习

   Sed Stream EDitor 的缩写,是 Unix 下常用的基于文件和管道的编辑工具,可以在手册中得到关于 sed 的详细信息。
  这里是一些有趣的 sed 脚本,假定我们正在处理一个叫做 price.txt 的文件。注意这些编辑并不会改变源文件, sed 只是处理源文件的每一行并把结果显示在标准输出中(当然很容易使用重定向来定制):
   sed 脚本 描述
   sed 's/^$/d' price.txt 删除所有空行
   sed 's/^[ \t]*$/d' price.txt 删除所有只包含空格或者制表符的行
sed 's/"//g' price.txt 删除所有引号
 

  awk将来再学习

   awk 是一种编程语言,可以用来对文本数据进行复杂的分析和处理。可以在手册中得到关于 awk 的详细信息。这个古怪的名字是它作者们的姓的缩写( Aho Weinberger Kernighan )。
  在 Aho Weinberger Kernighan 的书 The AWK Programming Language 中有很多很好的 awk 的例子,请不要让下面这些微不足道的脚本例子限制你对 awk 强大能力的理解。我们同样假定我们针对 price.txt 文件进行处理,跟 sed 一样, awk 也只是把结果显示在终端上。
   awk 脚本 描述
   awk ' !~ /^$/' price.txt 删除所有空行
   awk 'NF > 0' price.txt awk 中一个更好的删除所有空行的办法
   awk ' ~ /^[JT]/ ' price.txt 打印所有第二个字段是 'J' 或者 'T' 打头的行中的第三个字段
   awk ' !~ /[Mm]isc/ {print + }' price.txt 针对所有第二个字段不包含 'Misc' 或者 'misc' 的行,打印第 3 和第 4 列的和(假定为数字)
   awk ' !~ /^[0-9]+\.[0-9]*$/ ' price.txt 打印所有第三个字段不是数字的行,这里数字是指 d.d 或者 d 这样的形式,其中 d 0 9 的任何数字
awk ' ~ /John|Fred/ ' price.txt 如果第二个字段包含 'John' 或者 'Fred' 则打印整行
 

  grep

   grep 是一个用来在一个或者多个文件或者输入流中使用 RE 进行查找的程序。它的 name 编程语言可以用来针对文件和管道进行处理。可以在手册中得到关于 grep 的完整信息。这个同样古怪的名字来源于 vi 的一个命令, g/re/p ,意思是 global regular expression print
  下面的例子中我们假定在文件 phone.txt 中包含以下的文本,――其格式是姓加一个逗号,然后是名,然后是一个制表符,然后是电话号码:
   Francis, John 5-3871
   Wong, Fred 4-4123
   Jones, Thomas 1-4122
   Salazar, Richard 5-2522
   grep 命令 描述
   grep '\t5-...1' phone.txt 把所有电话号码以 5 开头以 1 结束的行打印出来,注意制表符是用 \t 表示的
   grep '^S[^ ]* R' phone.txt 打印所有姓以 S 打头和名以 R 打头的行
   grep '^[JW]' phone.txt 打印所有姓开头是 J 或者 W 的行
   grep '^....\t' phone.txt 打印所有姓是 4 个字符的行,注意制表符是用 \t 表示的
   grep -v '^[JW]' phone.txt 打印所有不以 J 或者 W 开头的行
   grep '^[M-Z]' phone.txt 打印所有姓的开头是 M Z 之间任一字符的行
   grep '^[M-Z].*[12]' phone.txt 打印所有姓的开头是 M Z 之间任一字符,并且点号号码结尾是 1 或者 2 的行

  egrep

   egrep grep 的一个扩展版本,它在它的正则表达式中支持更多的元字符。下面的例子中我们假定在文件 phone.txt 中包含以下的文本,――其格式是姓加一个逗号,然后是名,然后是一个制表符,然后是电话号码:
   Francis, John 5-3871
   Wong, Fred 4-4123
   Jones, Thomas 1-4122
   Salazar, Richard 5-2522
   egrep command Description
   egrep '(John|Fred)' phone.txt 打印所有包含名字 John 或者 Fred 的行
   egrep 'John|22$|^W' phone.txt 打印所有包含 John 或者以 22 结束或者以 W 开头的行
   egrep 'net(work)?s' report.txt report.txt 中找到所有包含 networks 或者 nets 的行
  正则表达式语法支持情况
  命令或环境 . [ ] ^ $ \( \) \{ \} ? + | ( )
 

  vi替换命令简介

   Vi 的替换命令:
   :ranges/pat1/pat2/g
  其中
   : 这是 Vi 的命令执行界面。
   range 是命令执行范围的指定,可以使用百分号( % )表示所有行,使用点( . )表示当前行,使用美元符号( $ )表示最后一行。你还可以使用行号,例如 10,20 表示第 10 20 行, .,$ 表示当前行到最后一行, .+2,$-5 表示当前行后两行直到全文的倒数第五行,等等。
   s 表示其后是一个替换命令。
   pat1 这是要查找的一个正则表达式,这篇文章中有一大堆例子。
   pat2 这是希望把匹配串变成的模式的正则表达式,这篇文章中有一大堆例子。
g 可选标志,带这个标志表示替换将针对行中每个匹配的串进行,否则则只替换行中第一个匹配串。
 
 

三:读后总结

Source Insight 里面不区分大小写搜索, grep [Aa][Bb]… 来实现
Source Insight 里面 Whole Words Only 匹配, grep 的实现,没有简单的直接方式,但是可以根据实际情况完成。
比如: egrep ‘\<word\>’ files ,这种情况可用于搜索 C 函数,变量等。
但是对于结构成员,可能需要:
grep ‘[ .>:]word’ files

你可能感兴趣的:(正则表达式,职场,休闲)