正在查找正则表达式以查找大字符串中引用的换行符(对于C#)

正在查找正则表达式以查找大字符串中引用的换行符(对于C#),c#,regex,C#,Regex,我有一个很大的字符串(我们称之为CSV文件,虽然它实际上不是一个,但现在更容易),我必须用C代码解析它。 解析过程的第一步只需使用StreamReader对象并调用ReadLine直到文件完成,即可将文件拆分为单独的行。但是,任何给定的行都可能包含一个带引号(单引号)的文字和嵌入的换行符。我需要找到这些换行符,并将它们临时转换为其他类型的标记或转义序列,直到我将文件拆分为一个行数组。然后我可以将它们更改回原来的位置 输入数据示例: 1,2,10,99,'Some text without a n

我有一个很大的字符串(我们称之为CSV文件,虽然它实际上不是一个,但现在更容易),我必须用C代码解析它。
解析过程的第一步只需使用
StreamReader
对象并调用
ReadLine
直到文件完成,即可将文件拆分为单独的行。但是,任何给定的行都可能包含一个带引号(单引号)的文字和嵌入的换行符。我需要找到这些换行符,并将它们临时转换为其他类型的标记或转义序列,直到我将文件拆分为一个行数组。然后我可以将它们更改回原来的位置

输入数据示例:

1,2,10,99,'Some text without a newline', true, false, 90
2,1,11,98,'This text has an embedded newline 
                and continues here', true, true, 90

我可以通过使用
string.IndexOf
来编写完成此任务所需的所有C#代码,以找到引用的部分并在其中查找换行符,但我认为正则表达式可能是更好的选择(即编辑:

对不起,我误解了你的帖子。如果您正在寻找正则表达式,那么这里有一个:

content = Regex.Replace(content, "'([^']*)\n([^']*)'", "'\1TOKEN\2'");
可能会有边缘情况和这两个问题,但我认为大多数情况下应该是可以的。正则表达式所做的是,它首先找到任何一对在它之间有\n的单引号,并用保留其间任何文本的标记\n替换它


但是,我还是会像下面@bryans解释的那样使用状态机。

如果将整个文件放入一个变量中,然后根据不带引号的换行符将其拆分,会怎么样?

因为这不是一个真正的CSV文件,它有任何模式吗

从您的示例来看,您似乎有: int,int,int,int,string,bool,bool,int

这构成了你的记录/对象

假设您的数据格式正确(我对您的来源了解不够,无法知道此假设的有效性);你可以:

  • 读你的台词
  • 使用状态机解析数据
  • 如果您的行结束,并且您正在解析字符串,请阅读下一行..并继续解析

  • 如果可能的话,我会避免使用正则表达式。

    使用C#2.0迭代器可以简化执行此类任务的状态机。希望这是我将要编写的最后一个CSV解析器。整个文件被视为一组可枚举字符串,即行/列。IEnumerable很好,因为它可以由LINQ操作符处理

    public class CsvParser
    {
        public char FieldDelimiter { get; set; }
    
        public CsvParser()
            : this(',')
        {
        }
    
        public CsvParser(char fieldDelimiter)
        {
            FieldDelimiter = fieldDelimiter;
        }
    
        public IEnumerable<IEnumerable<string>> Parse(string text)
        {
            return Parse(new StringReader(text));
        }
        public IEnumerable<IEnumerable<string>> Parse(TextReader reader)
        {
            while (reader.Peek() != -1)
                yield return parseLine(reader);
        }
    
        IEnumerable<string> parseLine(TextReader reader)
        {
            bool insideQuotes = false;
            StringBuilder item = new StringBuilder();
    
            while (reader.Peek() != -1)
            {
                char ch = (char)reader.Read();
                char? nextCh = reader.Peek() > -1 ? (char)reader.Peek() : (char?)null;
    
                if (!insideQuotes && ch == FieldDelimiter)
                {
                    yield return item.ToString();
                    item.Length = 0;
                }
                else if (!insideQuotes && ch == '\r' && nextCh == '\n') //CRLF
                {
                    reader.Read(); // skip LF
                    break;
                }
                else if (!insideQuotes && ch == '\n') //LF for *nix-style line endings
                    break;
                else if (ch == '"' && nextCh == '"') // escaped quotes ""
                {
                    item.Append('"');
                    reader.Read(); // skip next "
                }
                else if (ch == '"')
                    insideQuotes = !insideQuotes;
                else
                    item.Append(ch);
            }
            // last one
            yield return item.ToString();
        }
    
    }
    
    公共类CsvParser
    {
    公共字符字段分隔符{get;set;}
    公共CsvParser()
    :此(“,”)
    {
    }
    公共CsvParser(字符字段分隔符)
    {
    FieldDelimiter=字段分隔符;
    }
    公共IEnumerable解析(字符串文本)
    {
    返回解析(新的StringReader(文本));
    }
    公共IEnumerable解析(TextReader)
    {
    while(reader.Peek()!=-1)
    输出返回行(读卡器);
    }
    IEnumerable语法行(文本阅读器)
    {
    bool-insideQuotes=假;
    StringBuilder项=新的StringBuilder();
    while(reader.Peek()!=-1)
    {
    char ch=(char)reader.Read();
    char?nextCh=reader.Peek()>-1?(char)reader.Peek():(char?)null;
    if(!insideQuotes&&ch==字段分隔符)
    {
    收益返回项.ToString();
    项目长度=0;
    }
    如果(!insideQuotes&&ch='\r'&&nextCh='\n')//CRLF
    {
    reader.Read();//跳过LF
    打破
    }
    else如果(!insidequeotes&&ch='\n')//LF用于*nix样式的行尾
    打破
    else if(ch='''&&nextCh=''')//转义引号
    {
    项目.附加(“”);
    reader.Read();//跳过下一步”
    }
    else如果(ch==“”)
    insideQuotes=!insideQuotes;
    其他的
    项目.附加(ch);
    }
    //最后一个
    收益返回项.ToString();
    }
    }
    
    请注意,文件是逐字符读取的,代码决定何时将换行符视为行分隔符或带引号字符串的一部分