正则表达式使用换行符拆分字符串(除非它在双引号之间)
Regex split a string using newline (unless it is between double quotes)
我正在处理一些带分隔符的文件。我需要做的第一件事是获取所有 "lines"。获取每一行后,我可以根据指定的分隔符进行拆分。因此,要获得我需要使用各种行名称 (\r\n、\r、\n) 拆分字符串的行。以下一直有效,直到我在双引号中遇到换行符:
return content.Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
因此,如果您考虑以下文本(我的原始文本用 \" 而不是 "")在双引号内转义了双引号,其中每一行都由行名称之一分隔,并且每个 field/column行中由竖线“|”字符分隔:
string s = "row1 col1|\"row1 \"\"col2a\"\"\r\nrow1 col2b\"|row1 col3\nrow2 col1|\"row2 \"\"col2a\"\"\rrow2 \"\"col2b\"\"\"|row2 col3\r\nrow3 col1|\"row3 col2a\nrow3 col2b\"|row3 col3";
等于以下字符串:
row1 col1|"row1 ""col2a""{CRLF}row1 ""col2b"""|row1 col3{CRLF}row2 col1|"row2 ""col2a" "{CRLF}row2 ""col2b"""|row2 col3{CRLF}row3 col1|"row3 col2a{CRLF}row3 col2b"|row3 col3
将上面的内容与我原来的方法拆分成 5 行:
string[] result = s.Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
但我想使用行分隔符 (\r\n, \r, \n) 将上面的内容拆分为 3 行:
result[0] == "row1 col1|\"row1 \"\"col2a\"\"\r\nrow1 col2b\"|row1 col3"
result[1] == "row2 col1|\"row2 \"\"col2a\"\"\rrow2 \"\"col2b\"\"\"|row2 col3"
result[2] == "row3 col1|\"row3 col2a\nrow3 col2b\"|row3 col3"
有没有人幸运地想出了一个正则表达式来拆分行(引号内除外)?
这是我最终得到的,感谢 Alan:
public string[] GetLines (string fileContent) {
Regex regex = new Regex(@"^([^""\r\n]*(?:(?:""[^""]*"")*[^""\r\n]*))", RegexOptions.Multiline);
MatchCollection matchCollection = regex.Matches(fileContent);
string[] result = new string[matchCollection.Count];
for (int i = 0; i < matchCollection.Count; i++) {
Match match = matchCollection[i];
result[i] = match.Value;
}
return result;
}
我会使用 Matches()
而不是 Split()
:
Regex r = new Regex(@"(?m)^[^""\r\n]*(?:(?:""[^""]*"")+[^""\r\n]*)*");
MatchCollection m = r.Matches(s);
内部 (?:(?:"[^"]*")+
匹配可能包含转义引号的双引号字符串。整个正则表达式匹配可能包含一个或多个双引号字符串的行。请注意,内部字符 类 ([^"]
) 可以匹配 \r
和 \n
,而外部字符 ([^"\r\n]
) 明确排除它们。行开始锚点(^
在多行模式下)防止真实匹配之间的虚假空匹配。
这是 demo。 (它在 PCRE 中,但我也在 .NET 中对其进行了测试。)
您可以尝试以下正则表达式:
var fieldSeparator = "|";
var strRx = $@"""[^""\r\n]*""{fieldSeparator}[^|]+(?:\s*)";
var rx = new Regex(strRx);
var data = "row1 col1|\"row1 \\"col2a\\"\r\nrow1 \\"col2b\\"\"|row1 col3\nrow2 col1|\"row2 col2a\rrow2 col2b\"";
var m = rx.Match(data);
while (m.Success)
{
Console.WriteLine(m.Value);
m = m.NextMatch();
}
只需将 fieldSeparator
值替换为您要使用的任何字段分隔符即可。
以上代码片段产生以下输出:
row1 col1
"row1 \"
col2a\"
row1 \"col2b\""
row1 col3
row2 col1
row2 col2b"
我正在处理一些带分隔符的文件。我需要做的第一件事是获取所有 "lines"。获取每一行后,我可以根据指定的分隔符进行拆分。因此,要获得我需要使用各种行名称 (\r\n、\r、\n) 拆分字符串的行。以下一直有效,直到我在双引号中遇到换行符:
return content.Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
因此,如果您考虑以下文本(我的原始文本用 \" 而不是 "")在双引号内转义了双引号,其中每一行都由行名称之一分隔,并且每个 field/column行中由竖线“|”字符分隔:
string s = "row1 col1|\"row1 \"\"col2a\"\"\r\nrow1 col2b\"|row1 col3\nrow2 col1|\"row2 \"\"col2a\"\"\rrow2 \"\"col2b\"\"\"|row2 col3\r\nrow3 col1|\"row3 col2a\nrow3 col2b\"|row3 col3";
等于以下字符串:
row1 col1|"row1 ""col2a""{CRLF}row1 ""col2b"""|row1 col3{CRLF}row2 col1|"row2 ""col2a" "{CRLF}row2 ""col2b"""|row2 col3{CRLF}row3 col1|"row3 col2a{CRLF}row3 col2b"|row3 col3
将上面的内容与我原来的方法拆分成 5 行:
string[] result = s.Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
但我想使用行分隔符 (\r\n, \r, \n) 将上面的内容拆分为 3 行:
result[0] == "row1 col1|\"row1 \"\"col2a\"\"\r\nrow1 col2b\"|row1 col3"
result[1] == "row2 col1|\"row2 \"\"col2a\"\"\rrow2 \"\"col2b\"\"\"|row2 col3"
result[2] == "row3 col1|\"row3 col2a\nrow3 col2b\"|row3 col3"
有没有人幸运地想出了一个正则表达式来拆分行(引号内除外)?
这是我最终得到的,感谢 Alan:
public string[] GetLines (string fileContent) {
Regex regex = new Regex(@"^([^""\r\n]*(?:(?:""[^""]*"")*[^""\r\n]*))", RegexOptions.Multiline);
MatchCollection matchCollection = regex.Matches(fileContent);
string[] result = new string[matchCollection.Count];
for (int i = 0; i < matchCollection.Count; i++) {
Match match = matchCollection[i];
result[i] = match.Value;
}
return result;
}
我会使用 Matches()
而不是 Split()
:
Regex r = new Regex(@"(?m)^[^""\r\n]*(?:(?:""[^""]*"")+[^""\r\n]*)*");
MatchCollection m = r.Matches(s);
内部 (?:(?:"[^"]*")+
匹配可能包含转义引号的双引号字符串。整个正则表达式匹配可能包含一个或多个双引号字符串的行。请注意,内部字符 类 ([^"]
) 可以匹配 \r
和 \n
,而外部字符 ([^"\r\n]
) 明确排除它们。行开始锚点(^
在多行模式下)防止真实匹配之间的虚假空匹配。
这是 demo。 (它在 PCRE 中,但我也在 .NET 中对其进行了测试。)
您可以尝试以下正则表达式:
var fieldSeparator = "|";
var strRx = $@"""[^""\r\n]*""{fieldSeparator}[^|]+(?:\s*)";
var rx = new Regex(strRx);
var data = "row1 col1|\"row1 \\"col2a\\"\r\nrow1 \\"col2b\\"\"|row1 col3\nrow2 col1|\"row2 col2a\rrow2 col2b\"";
var m = rx.Match(data);
while (m.Success)
{
Console.WriteLine(m.Value);
m = m.NextMatch();
}
只需将 fieldSeparator
值替换为您要使用的任何字段分隔符即可。
以上代码片段产生以下输出:
row1 col1
"row1 \"
col2a\"
row1 \"col2b\""
row1 col3
row2 col1
row2 col2b"