忽略Double引号中的Rogue引用

时间:2013-08-08 08:16:38

标签: c# .net string

我有一个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" 结果

  • “bla bla”
  • “bla bla2”
  • 3
  • 4
  • “5”
  • “BLA” BLA”, “结束”

如何更改我的代码以允许流氓"

“有效”关闭引号后面总是后跟逗号(,)或控制换行符

这似乎解决了它

// 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';

3 个答案:

答案 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"

显然,这需要适应您的代码,并且它不是最佳解决方案(特别是如果引号之间有,),但它可能比尝试处理任何数量的“流氓”更容易引号。