正则表达式小技巧(不断更新中...)
我们使用正则表达式大多是在做输入验证的时候,也就是仅仅匹配一个符合条件的结果,但是如果我们解析一些特殊格式的文本,需要多个匹配结果,那么该如何获得多个匹配结果呢?下面来介绍两种方法:
方法一:
使用Matches方法,获得MatchCollection结果,遍历MatchCollection取得匹配的结果。
string equ = @"\w*@.*"; Regex rgx = new Regex(@"\d+?\d+_?\d*", RegexOptions.IgnoreCase); foreach (Match m in rgx.Matches(equ)) // 使用 Matches 方法 { Console.WriteLine(m.Value); }
方法二:
使用NextMatch方法,当匹配成功时,继续向下匹配。
Match m = rgx.Match(equ); // 也可以使用 Match 方法匹配第一个 while (m.Success) { Console.WriteLine(m.Value); m = m.NextMatch(); // 使用 NextMatch 获得下一个 }
RegexOptions枚举提供一些正则的匹配选项,如忽略大小写、多行模式、单号模式等,下面是MSDN的说明:
一个 RegexOptions 值,它可作为参数提供给 Regex 类的下列成员:
Regex.Regex(String, RegexOptions) 类构造函数。
Regex.Split(String, String, RegexOptions) 方法。
Regex.IsMatch(String, String, RegexOptions) 方法。
Regex.Match(String, String, RegexOptions) 方法。
Regex.Matches(String, String, RegexOptions) 方法。
Regex.Replace(String, String, String, RegexOptions) 和 Regex.Replace(String, String, MatchEvaluator, RegexOptions) 方法。
1、使用Group和Capture
string pattern = @"(\b(\w+?)[,:;]?\s?)+[?.!]"; string input = "This is one sentence. This is a second sentence."; Match match = Regex.Match(input, pattern); Console.WriteLine("Match: " + match.Value); int groupCtr = 0; foreach (Group group in match.Groups) { groupCtr++; Console.WriteLine(String.Format(" Group {0}: '{1}'", groupCtr, group.Value)); int captureCtr = 0; foreach (Capture capture in group.Captures) { captureCtr++; Console.WriteLine(String.Format(" Capture {0}: '{1}'", captureCtr, capture.Value)); } }
Group及正则表达式中的分组,在这个例子中,整个正则表达式算一个分组,索引是1,(\b(\w+?)[,:;]?\s?)算是一个分组,索引是2,(\w+?)是一个分组,索引是3.所以这个会输出三个分组。
在此正则表达式模式中,子模式 (\w+?) 旨在匹配一个句子中的多个单词。 但是,Group 对象的值只表示 (\w+?) 捕获的最后一个匹配,而 Captures 属性返回表示所有捕获对象的 CaptureCollection。 如输出所示,第二个捕获组的 CaptureCollection 包含四个对象。 其中的最后一项对应于 Group 对象。
注意:正则中的分组索引是从1开始的。
输出如下结果:
可以看到Group3的匹配结果没有空格。
2、非捕获组
以下分组构造不会捕获由子表达式匹配的子字符串:
(?:subexpression)
其中子表达式为任何有效正则表达式模式。 当一个限定符应用到一个组,但组捕获的子字符串并非所需时,通常会使用非捕获组构造。
修改一中的正则表达式为:
string pattern = @"(\b(?:\w+?)[,:;]?\s?)+[?.!]";
会发现输出结果只有两个分组,而不会捕获(?:\w+?)这个分组。
3、分组命名
以下分组构造捕获匹配的子表达式,并允许你按名称或编号访问它:
(?<name>subexpression) 或: (?'name' subexpression)
其中名称是有效的组名称,而子表达式是任何有效的正则表达式模式。 名称不得包含任何标点符号字符,并且不能以数字开头。
下面是MSDN上面的一个例子,找到重复单词的位置,并输出在哪个单词之后。
using System; using System.Text.RegularExpressions; public class Example { public static void Main() { string pattern = @"(?<duplicateWord>\w+)\s\k<duplicateWord>\W(?<nextWord>\w+)"; string input = "He said that that was the the correct answer."; foreach (Match match in Regex.Matches(input, pattern, RegexOptions.IgnoreCase)) Console.WriteLine("A duplicate '{0}' at position {1} is followed by '{2}'.", match.Groups["duplicateWord"].Value, match.Groups["duplicateWord"].Index, match.Groups["nextWord"].Value); } } // The example displays the following output: // A duplicate 'that' at position 8 is followed by 'was'. // A duplicate 'the' at position 22 is followed by 'correct'.
可用以下方式访问已命名的捕获组:
1、通过使用正则表达式中的命名的反向引用构造。 使用语法 \k<名称> 在同一正则表达式中引用匹配的子表达式,其中名称是捕获子表达式的名称。
2、通过使用正则表达式中的反向引用构造。 使用语法 \数字 在同一正则表达式中引用匹配的子表达式,其中数字是捕获的表达式的初始数字。 已命名的匹配子表达式在匹配子表达式后从左到右连续编号。
3、通过使用 Regex.Replace 或 Match.Result 方法调用中的${名称}替换序列,其中名称为捕获的子表达式的名称。
4、通过使用 Regex.Replace 或 Match.Result 方法调用中的$编号替换序列,其中编号为捕获的子表达式的序号。
使用[\u4e00-\u9fa5]可以匹配任意汉字。
这里是几个主要非英文语系字符范围
2E80~33FFh:中日韩符号区。收容康熙字典部首、中日韩辅助部首、注音符号、日本假名、韩文音符,中日韩的符号、标点、带圈或带括符文数字、月份,以及日本的假名组合、单位、年号、月份、日期、时间等。
3400~4DFFh:中日韩认同表意文字扩充A区,总计收容6,582个中日韩汉字。
4E00~9FFFh:中日韩认同表意文字区,总计收容20,902个中日韩汉字。
A000~A4FFh:彝族文字区,收容中国南方彝族文字和字根。
AC00~D7FFh:韩文拼音组合字区,收容以韩文音符拼成的文字。
F900~FAFFh:中日韩兼容表意文字区,总计收容302个中日韩汉字。
FB00~FFFDh:文字表现形式区,收容组合拉丁文字、希伯来文、阿拉伯文、中日韩直式标点、小符号、半角符号、全角符号等。
比如需要匹配所有中日韩非符号字符,那么正则表达式应该是^[\u3400-\u9FFF]+$
理论上没错, 可是我到msn.co.ko随便复制了个韩文下来, 发现根本不对, 诡异
再到msn.co.jp复制了个'お', 也不得行..
然后把范围扩大到^[\u2E80-\u9FFF]+$, 这样倒是都通过了, 这个应该就是匹配中日韩文字的正则表达式了, 包括我們臺灣省還在盲目使用的繁體中文
而关于中文的正则表达式, 应该是^[\u4E00-\u9FFF]+$, 和论坛里常被人提起的^[\u4E00-\u9FA5]+$很接近
需要注意的是论坛里说的^[\u4E00-\u9FA5]+$这是专门用于匹配简体中文的正则表达式, 实际上繁体字也在里面, 我用测试器测试了下'中華人民共和國', 也通过了, 当然, ^[\u4E00-\u9FFF]+$也是一样的结果。