《c#10 in a nutshell》--- 读书随记(14)
Chapter 25. Regular Expressions
内容来自书籍《C# 10 in a Nutshell》
Author:Joseph Albahari
需要该电子书的小伙伴,可以留下邮箱,有空看到就会发送的
正则表达式语言识别字符模式。支持正则表达式的 .NET 类型基于 Perl 5正则表达式,并支持搜索和搜索/替换功能
正则表达式用于以下任务:
- 验证文本输入,如密码和电话号码
- 将文本数据解析为更结构化的表单
- 替换文档中的文本模式
所有的正则表达式类型都定义在System.Text.RegularExpressions命名空间
Regular Expression Basics
最常见的正则表达式运算符之一是量词。?是与前一项0或1次匹配的量词。换句话说?意味着可以选择。项目可以是单个字符,也可以是方括号中的复杂字符结构
Console.WriteLine (Regex.Match ("color",@"colou?r").Success);// True
Console.WriteLine (Regex.Match ("colour", @"colou?r").Success);// True
Console.WriteLine (Regex.Match ("colouur", @"colou?r").Success);// False
Regex.Match在较大的字符串中搜索。它返回的对象具有匹配的索引和长度以及实际匹配的值的属性
Match m = Regex.Match ("any colour you like", @"colou?r");
Console.WriteLine (m.Success); // True
Console.WriteLine (m.Index); // 4
Console.WriteLine (m.Length); // 6
Console.WriteLine (m.Value); // colour
Console.WriteLine (m.ToString()); // colour
默认情况下,正则表达式引擎从左向右工作,因此只返回最左边的匹配。可以使用 NextMatch 方法返回更多匹配项
Match m1 = Regex.Match ("One color? There are two colours in my head!",@"colou?rs?");
Match m2 = m1.NextMatch();
Console.WriteLine (m1); // color
Console.WriteLine (m2); // colours
Matches 方法返回所有匹配项在一个数组中
foreach (Match m in Regex.Matches("One color? There are two colours in my head!", @"colou?rs?"))
Console.WriteLine (m);
Compiled Regular Expressions
在前面的一些示例中,我们使用相同的模式重复调用静态 RegEx 方法。在这些情况下,另一种方法是使用模式和 RegexOptions.Compiled 实例化一个 Regex 对象,然后调用实例方法
Regex r = new Regex (@"sausages?", RegexOptions.Compiled);
Console.WriteLine (r.Match ("sausage")); // sausage
Console.WriteLine (r.Match ("sausages")); // sausages
RegexOptions.Compiled 指示 RegEx 实例使用轻量级代码生成(Reflection.Emit中的 DynamicMethod)来动态构建和编译适合该特定正则表达式的代码。这将导致更快的匹配,代价是初始编译成本。
RegexOptions 标志枚举允许您调整匹配行为。RegexOptions 的一个常见用途是执行不区分大小写的搜索
Console.WriteLine (Regex.Match ("a", "A", RegexOptions.IgnoreCase)); // a
这将应用当前区域性的大小写等价规则。使用 CultureInvariable 标志可以请求不变区域性
Console.WriteLine (Regex.Match ("a", "A", RegexOptions.IgnoreCase
| RegexOptions.CultureInvariant));

Character Escapes
正则表达式有一些元字符,用于特殊功能:
\ * + ? | { [ () ^ $ . #
要从字面上使用元字符,必须在字符前加上反斜杠或转义
Console.WriteLine (Regex.Match ("what?", @"what\?")); // what? (correct)
Character Sets

Quantifiers

Greedy Versus Lazy Quantifiers
量词默认是贪婪的,贪婪的量词尽可能多地重复匹配;懒惰是尽可能少地匹配,需要懒惰,可以给量词加上 ? 后缀
Zero-Width Assertions
正则表达式语言允许您通过后视(lookbehind)、前视(lookahead)、锚(anchors)和单词边界(word boundaries),对匹配之前或之后应该发生的事情设置条件。这些称为零宽度断言,因为它们不会增加匹配本身的宽度(或长度)。
Lookahead and Lookbehind
(?=expr) 构造检查后面的文本是否与 expr 匹配,而不在结果中包含 expr。这就是所谓的 positive lookahead
Console.WriteLine (Regex.Match ("say 25 miles more", @"\d+\s(?=miles)")); // 25
注意,结果中没有返回单词“ miles”,即使需要它来满足匹配
与上面相反的是 negative lookahead ,(?!expr)。这要求匹配之后不能跟随 expr
string regex = "(?i)good(?!.*(however|but))";
Console.WriteLine (Regex.IsMatch ("Good work! But...", regex)); // False
Console.WriteLine (Regex.IsMatch ("Good work! Thanks!", regex)); // True
(?<=expr)是一个 positive lookbehind,表示在匹配之前需要满足条件
(?<!expr)是和上面的相反 negative lookbehind,要求匹配之前不能有指定的表达式
Anchors
^ 匹配字符串的开始;$ 匹配字符串的结尾
Word Boundaries
匹配单词的边界,是匹配位置,而不会被捕获,就是是^和$一样
Groups
有时,将正则表达式分隔成一系列子表达式或组是有用的,比如,匹配电话\d{3}-\d{3}-\d{4}
假设我们想把它分成两组: 区号和本地号码。(\d{3})-(\d{3}-\d{4})
Match m = Regex.Match ("206-465-1918", @"(\d{3})-(\d{3}-\d{4})");
Console.WriteLine (m.Groups[1]); // 206
Console.WriteLine (m.Groups[2]); // 465-1918
组是正则表达式语言本身的一部分。这意味着可以在正则表达式中引用组。\n 语法允许您在表达式中按组号 n 对组进行索引。
foreach (Match m in Regex.Matches ("pop pope peep", @"\b(\w)\w+\1\b"))
Console.Write (m + " "); // pop peep
Named Groups
string regEx =
@"\b" + // word boundary
@"(?'letter'\w)" + // match first letter, and name it 'letter'
@"\w+" + // match middle letters
@"\k'letter'" + // match last letter, denoted by 'letter'
@"\b"; // word boundary
foreach (Match m in Regex.Matches ("bob pope peep", regEx))
Console.Write (m + " "); // bob peep
有两种命名形式:
(?'group-name'group-expr)或者(?<group-name>group-expr)
有两种使用形式:
\k'group-name'或者\k<group-name>
Replacing and Splitting Text
string find = @"\bcat\b";
string replace = "dog";
Console.WriteLine (Regex.Replace ("catapult the cat", find, replace));
替换字符串可以使用 $0 替换构造引用原始匹配。下面的示例将字符串中的数字包装在尖括号中
string text = "10 plus 20 makes 30";
Console.WriteLine (Regex.Replace (text, @"\d+", @"<$0>"));
// OUTPUT: <10> plus <20> makes <30>
也可以用$1, $2, $3或者${name}来引用匹配的组
MatchEvaluator Delegate
Replace 有一个重载,该重载接受每个匹配调用的 Matchevalator 委托。这允许您在正则表达式语言表达能力不足时,将替换字符串的内容委托给 C # 代码
Console.WriteLine (Regex.Replace ("5 is less than 10", @"\d+",
m => (int.Parse (m.Value) * 10).ToString()) );
// OUTPUT: 50 is less than 100
Splitting Text
foreach (string s in Regex.Split ("a5b7c", @"\d"))
Console.Write (s + " "); // a b c

浙公网安备 33010602011771号