我正在尝试编写一个可以从CSV文件中提取单个字段的正则表达式。
例如,如果在CSV文件中给出以下行:
123, Bob ,Bob, " Foo Bar ", "a, ""b"", c"
应该给出以下结果(没有 单引号):
'123'
'Bob'
'Bob'
' Foo Bar '
'a, "b", c'
请注意,除非它们在引号内,否则应修剪前导和尾随空格。
我并不担心无效的CSV行,例如没有匹配收尾报价的开放报价。根据上述规则,您可以放心地假设CSV文件完全有效。
如果单个Regex有困难,我也可以使用多个正则表达式。但我喜欢避免使用标准的C#操作,除非它们简单而简短。 (我不想最终编写大量代码。)
那么,有什么建议吗?
答案 0 :(得分:5)
我不会尝试编写我自己的csv解析器,那里有许多为你完成工作。
答案 1 :(得分:1)
有很多陷阱和错误可以使用正则表达式...尝试下面的代码它确实对我来说它很简单......
Using Reader As New Microsoft.VisualBasic.FileIO.TextFieldParser("C:\MyFile.csv")
Reader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited
Dim MyDelimeters(0 To 0) As String
Reader.HasFieldsEnclosedInQuotes = False
Reader.SetDelimiters(","c)
Dim currentRow As String()
While Not Reader.EndOfData
Try
currentRow = Reader.ReadFields()
Dim currentField As String
For Each currentField In currentRow
MsgBox(currentField)
Next
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message &
"is not valid and will be skipped.")
End Try
End While
End Using
如果发现方便,请标记为答案......;)
请在此处查看implementation ,,,
答案 2 :(得分:1)
我同意正则表达式不是“正确”的答案,但这是问题所要求的,我喜欢正确的正则表达式挑战。
下面的模式是我的standard CSV parsing regex的修改版本,它会移除空格并假设CSV完全符合您的要求。您未解决的问题的唯一部分是它不会删除转义/加倍引号。在模式之后给出了取消引号的示例。
当CSV文件/流的一行或多行/记录传递到下面的正则表达式时,它将返回每个非空行/记录的匹配项。每个匹配都将包含一个名为Value
的捕获组,其中包含该行/记录中捕获的值。
这是注释模式(测试它on Regexstorm.net):
(?<=\r|\n|^)(?!\r|\n|$) // Records start at the beginning of line (line must not be empty)
(?: // Group for each value and a following comma or end of line (EOL) - required for quantifier (+?)
[^\S\r\n]* // Removes leading spaces
(?: // Group for matching one of the value formats before a comma or EOL
"(?<Value>(?:[^"]|"")*)"| // Quoted value -or-
(?<Value>[^,\r\n]+)| // Unquoted/open ended quoted value -or-
(?<Value>) // Empty value before comma (before EOL is excluded by "+?" quantifier later)
)
[^\S\r\n]* // Removes trailing spaces
(?:,|(?=\r|\n|$)) // The value format matched must be followed by a comma or EOL
)+? // Quantifier to match one or more values (non-greedy/as few as possible to prevent infinite empty values)
(?:(?<=,)(?<Value>))? // If the group of values above ended in a comma then add an empty value to the group of matched values
(?:\r\n|\r|\n|$) // Records end at EOL
这是没有所有注释或空格的原始模式。
(?<=\r|\n|^)(?!\r|\n|$)(?:[^\S\r\n]*(?:"(?<Value>(?:[^"]|"")*)"|(?<Value>[^,\r\n]+)|(?<Value>))[^\S\r\n]*(?:,|(?=\r|\n|$)))+?(?:(?<=,)(?<Value>))?(?:\r\n|\r|\n|$)
而且,这是C#转义版本。
String CSVPattern=
@"(?<=\r|\n|^)(?!\r|\n|$)" +
@"(?:" +
@"[^\S\r\n]*" +
@"(?:" +
@"""(?<Value>(?:[^""]|"""")*)""|" +
@"(?<Value>[^,\r\n]+)|" +
@"(?<Value>)" +
@")" +
@"[^\S\r\n]*" +
@"(?:,|(?=\r|\n|$))" +
@")+?" +
@"(?:(?<=,)(?<Value>))?" +
@"(?:\r\n|\r|\n|$)";
关于如何使用正则表达式模式的示例(以及可以用此模式替换的原始模式)可以在我对类似问题here或C# pad here或{{3}的答案中找到。 }}
注意:以上示例包含取消/取消引号的逻辑,如下所示:
if (Capture.Length == 0 || Capture.Index == Record.Index || Record.Value[Capture.Index - Record.Index - 1] != '\"')
{
// No need to unescape/undouble quotes if the value is empty, the value starts
// at the beginning of the record, or the character before the value is not a
// quote (not a quoted value)
Console.WriteLine(Capture.Value);
}
else
{
// The character preceding this value is a quote
// so we need to unescape/undouble any embedded quotes
Console.WriteLine(Capture.Value.Replace("\"\"", "\""));
}
答案 3 :(得分:0)
您可以使用.NET框架中内置的TextFieldParser类。
要在C#应用程序中使用该类,您需要在以下位置添加Microsoft.VisualBasic.dll
的引用(假设您安装了默认设置)
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Microsoft.VisualBasic.dll
现在在你的C#类中有以下using语句:
using Microsoft.VisualBasic.FileIO