私は正規表現が「正しい」答えではないことに同意しますが、それは質問が求めたものであり、私は良い正規表現の挑戦が好きです。
以下のパターンは、スペースを削除し、CSVが要求どおりに完全であると想定する、標準のCSV解析正規表現の修正バージョンです。それによって対処されていないあなたの質問の唯一の部分は、それがエスケープされた/二重引用符を削除しないということです。引用符をエスケープ解除する例は、パターンの後に示されています。
CSVファイル/ストリームの1つ以上の行/レコードが以下の正規表現に渡されると、空でない各行/レコードの一致が返されます。各一致にはValue
、その行/レコードのキャプチャされた値を含むという名前のキャプチャグループが含まれます。
コメントされたパターンは次のとおりです(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|$)";
正規表現パターン(このパターンに置き換えることができる元のパターン)の使用方法の例は、ここの同様の質問に対する私の回答、またはここのC#パッド、またはここにあります。
注:上記の例には、以下に示すように、引用符をエスケープ解除/アンダブルするためのロジックが含まれています。
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("\"\"", "\""));
}