面试题答案
一键面试1. 预编译正则表达式
在C#中,Regex
类提供了CompileToAssembly
方法可以将正则表达式编译为程序集,这在需要多次使用相同正则表达式时能显著提高性能。不过,更常用的是在代码中预编译正则表达式,即通过创建Regex
对象并设置RegexOptions.Compiled
选项。
示例代码如下:
using System;
using System.Text.RegularExpressions;
class Program
{
private static readonly Regex emailRegex = new Regex(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}", RegexOptions.Compiled);
static void Main()
{
string text = "Here is an email: example@example.com";
Match match = emailRegex.Match(text);
if (match.Success)
{
Console.WriteLine(match.Value);
}
}
}
2. 字符集优化
- 缩小字符集范围:尽量精确地定义字符集。例如,在邮箱地址中,用户名部分通常由字母、数字、下划线、点、百分号、加号和减号组成,域名部分由字母、数字、点和减号组成。
- 避免使用贪婪量词:在可能的情况下,使用非贪婪量词。例如,如果有部分匹配规则可以使用
?
(非贪婪匹配)就尽量不用*
(贪婪匹配)或+
(贪婪匹配)。
以下是优化字符集后的正则表达式示例:
using System;
using System.Text.RegularExpressions;
class Program
{
private static readonly Regex emailRegex = new Regex(@"[a-zA-Z0-9._%+-]{1,64}@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", RegexOptions.Compiled);
static void Main()
{
string text = "Here is an email: example@example.com";
Match match = emailRegex.Match(text);
if (match.Success)
{
Console.WriteLine(match.Value);
}
}
}
这里对用户名部分限定了长度为1到64个字符,进一步优化了匹配。
3. 减少回溯
- 合理使用分组:避免不必要的分组。每个分组在匹配时都可能产生回溯,减少分组能减少回溯的可能性。
- 使用原子分组:如果某些部分匹配成功后不应该再回溯,可以使用原子分组
(?>pattern)
。不过在邮箱匹配中,一般标准的邮箱正则表达式较难用到原子分组,因为邮箱结构相对固定且不存在易产生复杂回溯的嵌套结构。
4. 多行匹配优化
如果文本文件是多行的,并且邮箱可能跨多行,要注意RegexOptions.Multiline
选项的使用。但如果不需要跨多行匹配邮箱,不设置这个选项能提高性能,因为设置后引擎需要处理更多的换行符相关逻辑。
示例代码如下(假设邮箱可能跨多行):
using System;
using System.Text.RegularExpressions;
class Program
{
private static readonly Regex emailRegex = new Regex(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}", RegexOptions.Compiled | RegexOptions.Multiline);
static void Main()
{
string text = "Here is an email:\nexample@example.com";
Match match = emailRegex.Match(text);
if (match.Success)
{
Console.WriteLine(match.Value);
}
}
}