我在解析CSV文件时看到了很多样本.但这个有点烦人的档案......
那么你如何解析这种CSV
"1",2010年1月2日,"样本("adasdad")asdada","我在门口"Stinky",所以我会该死的","AK"
在大多数情况下,最好的答案可能是@Jim Mischel.TextFieldParser对于大多数传统案例来说,似乎正是你想要的 - 虽然它奇怪地存在于Microsoft.VisualBasic命名空间中! 但这种情况并不常见.
我最后一次遇到这个问题的变化,我需要一些非常规的东西,我尴尬地放弃了regexp'ing并通过char检查剔除了一个char.有时,这不足以做到.如果你按字节推送,拆分字符串并不是一个问题.
所以我重写了这个案例作为字符串扩展.我认为这很接近.
请注意,这"I was pooping in the door "Stinky", so I'll be damn",是一个特别令人讨厌的案例.如果没有*** STINKY CONDITION ***下面的代码,您将获得I was pooping in the door "Stinky一个值和另一个值so I'll be damn".
对于任何匿名奇怪的分离器/转义情况,唯一的方法是使用某种算法来确定每行中"通常"的列数,然后在这种情况下检查固定长度字段,如您的AK州条目或其他一些可能的里程碑,作为不符合规范的列的一种规范化后备.但这可能是不需要的严重的疯狂逻辑,就像编码一样有趣.正如@Vash所指出的那样,你最好更好地遵循一些标准和编码更多的进攻性.
但这里的问题可能比这更容易. 唯一具有词汇意义的案例是你的例子中的一个",- 双引号,逗号,然后是空格.这就是*** STINKY CONDITION ***代码检查的内容.即便如此,这段代码变得比我想象的还要糟糕,这意味着你有一些奇怪的边缘情况,比如"This is also stinky," a f a b","Now what?" Heck,即使现在"A,"B","C"也没有在这段代码中工作,iirc,因为我把开始和结束字符视为已经逃脱前后固定.所以我们很大程度上回到了@Vash的评论!
为一行if陈述的所有括号道歉,但我现在陷入了一个StyleCop世界.我不一定建议你使用它 - strictEscapeToSplitEvaluation加上STINKY CONDITION使这有点复杂.但是值得注意的是,一个普通的csv解析器,它对于引用是明智的,直到变得单调乏味,但在其他方面是微不足道的.
namespace YourFavoriteNamespace
{
using System;
using System.Collections.Generic;
using System.Text;
public static class Extensions
{
public static Queue<string> SplitSeeingQuotes(this string valToSplit, char splittingChar = ',', char escapeChar = '"',
bool strictEscapeToSplitEvaluation = true, bool captureEndingNull = false)
{
Queue<string> qReturn = new Queue<string>();
StringBuilder stringBuilder = new StringBuilder();
bool bInEscapeVal = false;
for (int i = 0; i < valToSplit.Length; i++)
{
if (!bInEscapeVal)
{
// Escape values must come immediately after a split.
// abc,"b,ca",cab has an escaped comma.
// abc,b"ca,c"ab does not.
if (escapeChar == valToSplit[i] && (!strictEscapeToSplitEvaluation || (i == 0 || (i != 0 && splittingChar == valToSplit[i - 1]))))
{
bInEscapeVal = true; // not capturing escapeChar as part of value; easy enough to change if need be.
}
else if (splittingChar == valToSplit[i])
{
qReturn.Enqueue(stringBuilder.ToString());
stringBuilder = new StringBuilder();
}
else
{
stringBuilder.Append(valToSplit[i]);
}
}
else
{
// Can't use switch b/c we're comparing to a variable, I believe.
if (escapeChar == valToSplit[i])
{
// Repeated escape always reduces to one escape char in this logic.
// So if you wanted "I'm ""double quote"" crazy!" to come out with
// the double double quotes, you're toast.
if (i + 1 < valToSplit.Length && escapeChar == valToSplit[i + 1])
{
i++;
stringBuilder.Append(escapeChar);
}
else if (!strictEscapeToSplitEvaluation)
{
bInEscapeVal = false;
}
// *** STINKY CONDITION ***
// Kinda defense, since only `", ` really makes sense.
else if ('"' == escapeChar && i + 2 < valToSplit.Length &&
valToSplit[i + 1] == ',' && valToSplit[i + 2] == ' ')
{
i = i+2;
stringBuilder.Append("\", ");
}
// *** EO STINKY CONDITION ***
else if (i+1 == valToSplit.Length || (i + 1 < valToSplit.Length && valToSplit[i + 1] == splittingChar))
{
bInEscapeVal = false;
}
else
{
stringBuilder.Append(escapeChar);
}
}
else
{
stringBuilder.Append(valToSplit[i]);
}
}
}
// NOTE: The `captureEndingNull` flag is not tested.
// Catch null final entry? "abc,cab,bca," could be four entries, with the last an empty string.
if ((captureEndingNull && splittingChar == valToSplit[valToSplit.Length-1]) || (stringBuilder.Length > 0))
{
qReturn.Enqueue(stringBuilder.ToString());
}
return qReturn;
}
}
}
Run Code Online (Sandbox Code Playgroud)
可能值得一提的是,你给自己的"答案"在其示例字符串中没有"Stinky"问题.; ^)
[了解我们问你们三年后],我会说你们的例子并不像这里的人们那样疯狂.我可以看到想要将转义字符(在本例中")作为转义字符处理,只有当它们是拆分字符后的第一个值时,或者在找到一个开放转义后,只有在分割器之前找到转义字符时才停止 ; 在这种情况下,分离器显然是,.
如果您的CSV的行abc,bc"a,ca"b,我希望这意味着我们有三个值:abc,bc"a,和ca"b.
您的"The sample ("adasdad") asdada"列中的相同交易- 不开始和结束单元格值的引号不是转义字符,并且不一定需要加倍才能保持含义.所以我strictEscapeToSplitEvaluation在这里添加了一面旗帜.
请享用.; ^)
| 归档时间: |
|
| 查看次数: |
16406 次 |
| 最近记录: |