Как я могу оптимизировать производительность этого регулярного выражения? - PullRequest
3 голосов
/ 08 июля 2011

Я использую регулярное выражение для замены запятых, не содержащихся в текстовых кавычках, в пространства табуляции. Я запускаю регулярное выражение для содержимого файла через задачу сценария в SSIS. Содержимое файла более 6000 строк. Я видел пример использования регулярного выражения для содержимого файла, которое выглядело так:

String FileContent = ReadFile(FilePath, ErrInfo);        
Regex r = new Regex(@"(,)(?=(?:[^""]|""[^""]*"")*$)");
FileContent = r.Replace(FileContent, "\t");

Эта замена вполне может занять приятное время для файла приличного размера.

Есть ли более эффективный способ запустить это регулярное выражение? Будет ли быстрее читать файл построчно и выполнять регулярное выражение в строке?

Ответы [ 3 ]

6 голосов
/ 08 июля 2011

Кажется, вы пытаетесь преобразовать значения, разделенные запятыми (CSV), в значения, разделенные табуляцией (TSV).

В этом случае вам следует вместо этого попытаться найти библиотеку CSV и прочитать поля с этой библиотекой (и при необходимости преобразовать их в TSV).

Кроме того, вы можете проверить, есть ли в каждой строке кавычки, и соответственно использовать более простой метод.

4 голосов
/ 08 июля 2011

Проблема заключается в том, что у каждого запятого весь путь до конца выглядит до конца, что приводит к сложности O (n 2 ), что заметно на длинных входах. Вы можете сделать это за один проход, пропустив кавычки при замене:

Regex csvRegex = new Regex(@"
    (?<Quoted>
        ""                  # Open quotes
        (?:[^""]|"""")*     # not quotes, or two quotes (escaped)
        ""                  # Closing quotes
    )
    |                       # OR
    (?<Comma>,)             # A comma
    ",
RegexOptions.IgnorePatternWhitespace);
content = csvRegex.Replace(content,
                        match => match.Groups["Comma"].Success ? "\t" : match.Value);

Здесь мы сопоставляем свободные команды и строки в кавычках. Метод Replace принимает обратный вызов с условием, которое проверяет, нашли ли мы запятую или нет, и заменяется соответствующим образом.

2 голосов
/ 08 июля 2011

Самая простая оптимизация будет

Regex r = new Regex(@"(,)(?=(?:[^""]|""[^""]*"")*$)", RegexOptions.Compiled);
foreach (var line in System.IO.File.ReadAllLines("input.txt"))
    Console.WriteLine(r.Replace(line, "\t"));

Я не профилировал это, но я не удивлюсь, если бы ускорение было огромным.

Если этого недостаточно, я предлагаю немного ручного труда:

var input = new StreamReader(File.OpenRead("input.txt"));

char[] toMatch = ",\"".ToCharArray ();
string line;
while (null != (line = input.ReadLine()))
{
    var result = new StringBuilder(line);
    bool inquotes = false;

    for (int index=0; -1 != (index = line.IndexOfAny (toMatch, index)); index++)
    {
        bool isquote = (line[index] == '\"');
        inquotes = inquotes != isquote;

        if (!(isquote || inquotes))
            result[index] = '\t';
    }
    Console.WriteLine (result);
}

PS: Я предположил, @"\t" было опечаткой для "\t", но, возможно, это не так:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...