寻找正则表达式以大字符串查找带引号的换行符(适用于C#)

寻找正则表达式以大字符串查找带引号的换行符(适用于C#)

Looking for Regex to find quoted newlines in a big string (for C#)

我有一个很大的字符串(我称它为CSV文件,尽管实际上不是一个,但现在会更简单),我必须在C#代码中进行解析。
解析过程的第一步是通过仅使用StreamReader对象并调用ReadLine直到文件通过,将文件分成几行。 但是,任何给定的行都可能包含带引号(单引号)的文字和嵌入的换行符。 我需要找到这些换行符,并将它们临时转换为其他类型的令牌或转义序列,直到将文件拆分成行数组为止。然后可以将其改回。

输入数据示例:

1
2
3
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#代码,但我认为正则表达式可能是一个更好的选择(即,现在我有两个问题)


使用C#2.0迭代器使完成此类工作的状态机变得容易。希望这是我将要编写的最后一个CSV解析器。整个文件被视为一串可枚举的字符串,即行/列。 IEnumerable很棒,因为它可以由LINQ运算符处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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 == '\
'
&& nextCh == '\
'
) //CRLF
            {
                reader.Read(); // skip LF
                break;
            }
            else if (!insideQuotes && ch == '\
'
) //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();
    }

}

请注意,逐字符读取文件,其代码决定何时将换行符视为行定界符或带引号的字符串的一部分。


由于这不是真正的CSV文件,因此它具有任何形式的架构吗?

从您的示例中,您看起来像:
int,int,int,int,string,bool,bool,int

这样就构成了您的记录/对象。

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

  • 阅读您的台词。
  • 使用状态机来解析您的数据。
  • 如果您的行结束,并且您正在解析字符串,请阅读下一行并继续进行解析。
  • 如果可能,我会避免使用正则表达式。


    如果将整个文件放入一个变量,然后根据未引用的换行符将其拆分怎么办?


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

    1
    2
    content = Regex.Replace(content,"'([^']*)\
    ([^']*)'"
    ,"'\\1TOKEN\\2'");

    可能存在一些极端情况,并且存在两个问题,但我认为大多数时候都可以。 Regex的作用是,它首先找到之间有\ n的任何一对单引号,然后用TOKEN替换该\ n并保留中间的任何文本。

    但是仍然,我会像下面的@bryansh一样去状态机。


    推荐阅读