我有一个csv解析器的代码
string input = wholeFile;
IList<string> wholeFileArray = new List<string>();
int start = 0;
bool inQuotes = false;
for (int current = 0; current < input.Length; current++)
{
// test each character before and after to determine if it is a valid quote, or a quote within a quote.
int test_backward = (current == 0 ? 1 : current) - 1;
int test_forward = (current == input.Length - 1 ? input.Length - 2 : current) + 1;
bool valid_quote = input[test_backward] == ',' || input[test_forward] == ',' || input[test_forward] == '\r';
if (input[current] == '\"') // toggle state
{
inQuotes = !inQuotes;
}
bool atLastChar = (current == input.Length - 1);
if (atLastChar)
{
wholeFileArray.Add(input.Substring(start));
}
else if (input[current] == ',' && !inQuotes)
{
wholeFileArray.Add(input.Substring(start, current - start));
start = current + 1;
}
}
如果,
不在双引号,
字符串中,则需要一个字符串并将其拆分为"something,foobar"
。
我的问题是我的字符串中的流氓"
搞乱了我的整个过程。
EX:"bla bla","bla bla2",3,4,"5","bla"bla","End"
结果
如何更改我的代码以允许流氓"
“有效”关闭引号后面总是后跟逗号(,)或控制换行符
加 这似乎解决了它
// test each character before and after to determine if it is a valid quote, or a quote within a quote.
int test_backward = (current == 0 ? 1 : current) - 1;
int test_forward = (current == input.Length - 1 ? input.Length - 2 : current) + 1;
bool valid_quote = input[test_backward] == ',' || input[test_forward] == ',' || input[test_forward] == '\r';
答案 0 :(得分:2)
尝试这样的事情:
if (input[current] == '"' && // 1
(!inQuotes || // 2
current + 1 == input.Length || // 3
input[current + 1] == '\r' || // 4
input[current + 1] == '\n' || // 5
(input[current + 1] == ',' && // 6
(current + 2 == input.Length || // 7
input[current + 2] == '\r' || // 8
input[current + 2] == '\n' || // 9
input[current + 2] == '"' || // 10
(input[current + 2] >= '0' && input[current + 2] <= '9'))))) // 11
// toggle state
但请注意,您想要做的事情在各种概念层面都是错误的。
相关引用是一个开头报价 2 或一个引号,它是字符串 3 的最后一个字符,或后跟\r
4 或\n
5 或后跟,
6 ,后者又是\r
6 的最后一个字符字符串 7 或后跟\n
8 或"
9 或引用{{ 1}} 10 或数字 11 。
答案 1 :(得分:1)
如果您可以选择基于bnf执行此操作,那么这是一个相当简单的语法。下面是使用fsyacc(可以从C#中使用)的样子。
start: lines
lines: line lines {$1::$2}
| {[]}
line: val vals {$1::$2}
| {[]}
val : QUOTE STR QUOTE COMMA {$2}
| QUOTE STR QUOTE STR QUOTE COMMA { $2 + "\"" + $4 }
| QUOTE STR QUOTE EOL {$2}
| QUOTE STR QUOTE STR QUOTE EOL { $2 + "\"" + $4 }
| QUOTE STR QUOTE EOF {$2}
| QUOTE STR QUOTE STR QUOTE EOF { $2 + "\"" + $4 }
制作val
也表明它是一个不洁的语法,因为你需要下一个标记来确定要做什么。如果有可能要求每一行以换行符(包括最后一行)结束,那么val可以简化为4而不是6,并要求每行以逗号结尾将其降为2。相当多的语法可以通过这种方式简化(通过要求每个语句以特定的字符结尾),这是c ++使用的方式;
答案 2 :(得分:0)
作为替代方案,只要您在引号内不会有,
,就可以查看Microsoft.VisualBasic.FileIO.TextFieldParser。
以下代码段:
using Microsoft.VisualBasic.FileIO;
using (TextFieldParser parser = new TextFieldParser(fileName))
{
parser.Delimiters = new string[] { "," };
while (!parser.EndOfData)
{
string[] fields = parser.ReadFields();
}
}
上面的代码片段生成一个包含您的采样行的数组,如下所示:
"bla bla" "bla bla2" 3 4 5 "bla"bla" "End"
显然,这需要适应您的代码,并且它不是最佳解决方案(特别是如果引号之间有,
),但它可能比尝试处理任何数量的“流氓”更容易引号。