标记化中奇怪的正则表达式行为
weird regex behavior in the tokenization
我正在使用以下正则表达式进行标记化:
reg = new Regex("([ \t{}%$^&*():;_–`,\-\d!\"?\n])");
正则表达式应该在以后过滤掉所有内容,但是我遇到问题的输入字符串格式如下:
; "string1"; "string2"; "string...n";
字符串的结果:; "social life"; "city life"; "real life"
据我所知应该如下所示:
; White " social White life " ; White " city White life " ; White " real White life "
但是有一个问题,我得到以下形式的输出
; empty White empty " social White life " empty ; empty White empty " city White life " empty ; empty White empty " real White life " empty
White:表示白色-Space,
empty: 表示拆分数组中的条目为空。
我的拆分代码如下:
string[] ret = reg.Split(input);
for (int i = 0; i < ret.Length; i++)
{
if (ret[i] == "")
Response.Write("empty<br>");
else
if (ret[i] == " ")
Response.Write("White<br>");
else
Response.Write(ret[i] + "<br>");
}
为什么我得到这些空条目?特别是当 ;
后跟 space 后跟 "
时,结果如下所示:
; empty White empty "
我可以解释为什么命令添加空条目吗?以及如何在没有任何额外的 O(n) 复杂性或使用其他数据结构作为 ret
的情况下删除它们
根据我的经验,在正则表达式匹配时拆分几乎总是不是最好的主意。通过简单匹配你会得到更好的结果。
正则表达式非常适合标记化目的,因为它们可以让您非常轻松地实现状态机,只需看一下:
\G(?:
(?<string> "(?>[^"\]+|\.)*" )
| (?<separator> ; )
| (?<whitespace> \s+ )
| (?<invalid> . )
)
Demo - 当然要与 RegexOptions.IgnorePatternWhitespace
一起使用。
在这里,每个匹配项将具有以下属性:
- 它将在上一场比赛结束时开始,因此不会有不匹配的文本
- 它将包含正好个匹配组
- 组名告诉你代币类型
- 您可以忽略
whitespace
组,如果遇到匹配的 invalid
组,您应该报错。
string
组将匹配整个带引号的字符串,它可以处理字符串中的转义,例如 \"
。
invalid
组应始终排在模式的最后。您可以为其他类型添加规则。
一些示例代码:
var regex = new Regex(@"
\G(?:
(?<string> ""(?>[^""\]+|\.)*"" )
| (?<separator> ; )
| (?<whitespace> \s+ )
| (?<invalid> . )
)
", RegexOptions.IgnorePatternWhitespace);
var input = "; \"social life\"; \"city life\"; \"real life\"";
var groupNames = regex.GetGroupNames().Skip(1).ToList();
foreach (Match match in regex.Matches(input))
{
var groupName = groupNames.Single(name => match.Groups[name].Success);
var group = match.Groups[groupName];
Console.WriteLine("{0}: {1}", groupName, group.Value);
}
这会产生以下结果:
separator: ;
whitespace:
string: "social life"
separator: ;
whitespace:
string: "city life"
separator: ;
whitespace:
string: "real life"
看看处理这些结果比使用拆分要容易得多?
我正在使用以下正则表达式进行标记化:
reg = new Regex("([ \t{}%$^&*():;_–`,\-\d!\"?\n])");
正则表达式应该在以后过滤掉所有内容,但是我遇到问题的输入字符串格式如下:
; "string1"; "string2"; "string...n";
字符串的结果:; "social life"; "city life"; "real life"
据我所知应该如下所示:
; White " social White life " ; White " city White life " ; White " real White life "
但是有一个问题,我得到以下形式的输出
; empty White empty " social White life " empty ; empty White empty " city White life " empty ; empty White empty " real White life " empty
White:表示白色-Space, empty: 表示拆分数组中的条目为空。
我的拆分代码如下:
string[] ret = reg.Split(input);
for (int i = 0; i < ret.Length; i++)
{
if (ret[i] == "")
Response.Write("empty<br>");
else
if (ret[i] == " ")
Response.Write("White<br>");
else
Response.Write(ret[i] + "<br>");
}
为什么我得到这些空条目?特别是当 ;
后跟 space 后跟 "
时,结果如下所示:
; empty White empty "
我可以解释为什么命令添加空条目吗?以及如何在没有任何额外的 O(n) 复杂性或使用其他数据结构作为 ret
根据我的经验,在正则表达式匹配时拆分几乎总是不是最好的主意。通过简单匹配你会得到更好的结果。
正则表达式非常适合标记化目的,因为它们可以让您非常轻松地实现状态机,只需看一下:
\G(?:
(?<string> "(?>[^"\]+|\.)*" )
| (?<separator> ; )
| (?<whitespace> \s+ )
| (?<invalid> . )
)
Demo - 当然要与 RegexOptions.IgnorePatternWhitespace
一起使用。
在这里,每个匹配项将具有以下属性:
- 它将在上一场比赛结束时开始,因此不会有不匹配的文本
- 它将包含正好个匹配组
- 组名告诉你代币类型
- 您可以忽略
whitespace
组,如果遇到匹配的invalid
组,您应该报错。
string
组将匹配整个带引号的字符串,它可以处理字符串中的转义,例如 \"
。
invalid
组应始终排在模式的最后。您可以为其他类型添加规则。
一些示例代码:
var regex = new Regex(@"
\G(?:
(?<string> ""(?>[^""\]+|\.)*"" )
| (?<separator> ; )
| (?<whitespace> \s+ )
| (?<invalid> . )
)
", RegexOptions.IgnorePatternWhitespace);
var input = "; \"social life\"; \"city life\"; \"real life\"";
var groupNames = regex.GetGroupNames().Skip(1).ToList();
foreach (Match match in regex.Matches(input))
{
var groupName = groupNames.Single(name => match.Groups[name].Success);
var group = match.Groups[groupName];
Console.WriteLine("{0}: {1}", groupName, group.Value);
}
这会产生以下结果:
separator: ;
whitespace:
string: "social life"
separator: ;
whitespace:
string: "city life"
separator: ;
whitespace:
string: "real life"
看看处理这些结果比使用拆分要容易得多?