Может быть лучшим алгоритмом для задачи является алгоритм быстрого целочисленного квадратного корня https://stackoverflow.com/a/51585204/5191852
Там @Kde утверждает, что три итерации метода Ньютона было бы достаточно для точности ± 1 для 32-битных целых чисел. Конечно, для 64-битных целых чисел требуется больше итераций, может быть 6 или 7.
Попробуйте использовать это регулярное выражение:
"[^"\r\n]*"|'[^'\r\n]*'|[^,\r\n]*
Regex regexObj = new Regex(@"""[^""\r\n]*""|'[^'\r\n]*'|[^,\r\n]*");
Match matchResults = regexObj.Match(input);
while (matchResults.Success)
{
Console.WriteLine(matchResults.Value);
matchResults = matchResults.NextMatch();
}
Выводы:
Почему бы не прислушаться к советам экспертов и Не использовать собственный парсер CSV .
Ваша первая мысль: «Мне нужно обрабатывать запятые внутри кавычки. "
Ваша следующая мысль будет:" О, дерьмо, мне нужно обрабатывать кавычки внутри кавычек. Экранированные кавычки. Двойные кавычки. Одинарные кавычки ... "
Это путь к безумию. Не пишите свои собственные. Найдите библиотеку с обширным охватом модульного тестирования, которая затрагивает все сложные моменты и прошла через ад за вас. Для .NET используйте бесплатную библиотеку с открытым исходным кодом FileHelpers .
это не регулярное выражение, но я использовал Microsoft.VisualBasic.FileIO.TextFieldParser для выполнения этого для файлов csv. да, может показаться немного странным добавление ссылки на Microsoft.VisualBasic в приложении C #, может быть, даже немного грязным, но эй, это работает.
А, RegEx. Теперь у вас две проблемы. ;)
Я бы использовал токенизатор / синтаксический анализатор, поскольку он довольно прост и, что более важно, его гораздо легче читать для дальнейшего обслуживания.
Это работает, например:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
class Program
{
static void Main(string[] args)
{
string myString = "cat,dog,\"0 = OFF, 1 = ON\",lion,tiger,'R = red, G = green, B = blue',bear";
Console.WriteLine("\nmyString is ...\n\t" + myString + "\n");
CsvParser parser = new CsvParser(myString);
Int32 lineNumber = 0;
foreach (string s in parser)
{
Console.WriteLine(lineNumber + ": " + s);
}
Console.ReadKey();
}
}
internal enum TokenType
{
Comma,
Quote,
Value
}
internal class Token
{
public Token(TokenType type, string value)
{
Value = value;
Type = type;
}
public String Value { get; private set; }
public TokenType Type { get; private set; }
}
internal class StreamTokenizer : IEnumerable<Token>
{
private TextReader _reader;
public StreamTokenizer(TextReader reader)
{
_reader = reader;
}
public IEnumerator<Token> GetEnumerator()
{
String line;
StringBuilder value = new StringBuilder();
while ((line = _reader.ReadLine()) != null)
{
foreach (Char c in line)
{
switch (c)
{
case '\'':
case '"':
if (value.Length > 0)
{
yield return new Token(TokenType.Value, value.ToString());
value.Length = 0;
}
yield return new Token(TokenType.Quote, c.ToString());
break;
case ',':
if (value.Length > 0)
{
yield return new Token(TokenType.Value, value.ToString());
value.Length = 0;
}
yield return new Token(TokenType.Comma, c.ToString());
break;
default:
value.Append(c);
break;
}
}
// Thanks, dpan
if (value.Length > 0)
{
yield return new Token(TokenType.Value, value.ToString());
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
internal class CsvParser : IEnumerable<String>
{
private StreamTokenizer _tokenizer;
public CsvParser(Stream data)
{
_tokenizer = new StreamTokenizer(new StreamReader(data));
}
public CsvParser(String data)
{
_tokenizer = new StreamTokenizer(new StringReader(data));
}
public IEnumerator<string> GetEnumerator()
{
Boolean inQuote = false;
StringBuilder result = new StringBuilder();
foreach (Token token in _tokenizer)
{
switch (token.Type)
{
case TokenType.Comma:
if (inQuote)
{
result.Append(token.Value);
}
else
{
yield return result.ToString();
result.Length = 0;
}
break;
case TokenType.Quote:
// Toggle quote state
inQuote = !inQuote;
break;
case TokenType.Value:
result.Append(token.Value);
break;
default:
throw new InvalidOperationException("Unknown token type: " + token.Type);
}
}
if (result.Length > 0)
{
yield return result.ToString();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
CSV не является обычным . Если ваш язык регулярных выражений не имеет достаточной мощности для обработки природы синтаксического анализа csv с сохранением состояния (маловероятно, что в MS нет), тогда любое решение на чистом регулярном выражении представляет собой список ошибок, ожидающих возникновения, когда вы попадаете в новый источник ввода, который не является довольно , обработанный последним регулярным выражением.
Чтение CSV не так сложно для написания в качестве конечного автомата, поскольку грамматика проста, но даже в этом случае вы должны учитывать: кавычки, запятые в кавычках, новые строки в кавычках, пустые поля.
Таким образом, вам, вероятно, следует просто воспользуйтесь чужим парсером CSV. Я рекомендую CSVReader для .Net
Функция:
private List<string> ParseDelimitedString (string arguments, char delim = ',')
{
bool inQuotes = false;
bool inNonQuotes = false; //used to trim leading WhiteSpace
List<string> strings = new List<string>();
StringBuilder sb = new StringBuilder();
foreach (char c in arguments)
{
if (c == '\'' || c == '"')
{
if (!inQuotes)
inQuotes = true;
else
inQuotes = false;
}else if (c == delim)
{
if (!inQuotes)
{
strings.Add(sb.Replace("'", string.Empty).Replace("\"", string.Empty).ToString());
sb.Remove(0, sb.Length);
inNonQuotes = false;
}
else
{
sb.Append(c);
}
}
else if ( !char.IsWhiteSpace(c) && !inQuotes && !inNonQuotes)
{
if (!inNonQuotes) inNonQuotes = true;
sb.Append(c);
}
}
strings.Add(sb.Replace("'", string.Empty).Replace("\"", string.Empty).ToString());
return strings;
}
Использование
string myString = "cat,dog,\"0 = OFF, 1 = ON\",lion,tiger,'R = red, G = green, B = blue',bear, text";
List<string> strings = ParseDelimitedString(myString);
foreach( string s in strings )
Console.WriteLine( s );
Вывод:
cat
dog
0 = OFF, 1 = ON
lion
tiger
R = red, G = green, B = blue
bear
text