Разделить, используя разделитель, за исключением случаев, когда разделитель экранирован - PullRequest
5 голосов
/ 10 декабря 2010

Я читаю данные буфера обмена, поступающие из Excel, используя

var stream = (System.IO.Stream) ( Forms.Clipboard.GetDataObject() ).GetData( Forms.DataFormats.CommaSeparatedValue ); * * 1004

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

 1,234,123.00    2,345.00    342.00      12,345.00

сохраняется как это:

\" 1,234,123.00 \",\" 2,345.00 \", 342.00 ,\" 12,345.00 \"

когда я действительно хочу это:

 1234123.00, 2345.00, 342.00, 12345.00

Ранее я использовал функцию clipData.Split(new string[] { "," }, StringSllitOptions.None)), чтобы превратить данные моего буфера обмена CSV в серию ячеек, но это не удается, если экранированный текст содержит запятые.


Я спрашиваю, может ли кто-нибудь придумать способ разбить эту строку на набор ячеек, игнорируя запятые, экранированные в битах \", поскольку именно так Excel выбирает экранирование ячеек, содержащих запятые.

Короче, как я могу превратить одну строку, содержащую это:

\" 1,234,123.00 \",\" 2,345.00 \", 342.00 ,\" 12,345.00 \"

в массив строк, содержащих это:

{ "1,234,123.00", "2,345.00", "342.00", "12,345.00" }

Не нарушая мою способность разбирать простую строку, разделенную запятой.

***** редактировать ***

Дополнительный вопрос (сформулированный как DFA) здесь: Разделить строку на основе того, когда детерминированные конечные автоматы достигают конечного состояния?

Ответы [ 5 ]

3 голосов
/ 10 декабря 2010

Прежде всего, я имел дело с данными из Excel раньше, и вы обычно видите значения, разделенные запятыми, и если значение считается строкой, оно будет иметь двойные кавычки (и может содержать запятые и двойные кавычки). Если он считается числовым, то двойных кавычек нет. Кроме того, если данные содержат двойную кавычку, которая будет разделена двойной кавычкой, например "". Итак, предполагая, что все это вот как я имел дело с этим в прошлом

public static IEnumerable<string> SplitExcelRow(this string value)
{
    value = value.Replace("\"\"", "&quot;");
    bool quoted = false;
    int currStartIndex = 0;
    for (int i = 0; i < value.Length; i++)
    {
        char currChar = value[i];
        if (currChar == '"')
        {
            quoted = !quoted;       
        }
        else if (currChar == ',')
        {
            if (!quoted)
            {
                yield return value.Substring(currStartIndex, i - currStartIndex)
                    .Trim()
                    .Replace("\"","")
                    .Replace("&quot;","\"");
                currStartIndex = i + 1;
            }
        }
    }
    yield return value.Substring(currStartIndex, value.Length - currStartIndex)
        .Trim()
        .Replace("\"", "")
        .Replace("&quot;", "\"");
}

Конечно, это предполагает, что поступающие данные действительны, поэтому, если у вас есть что-то вроде "fo,o"b,ar","bar""foo", это не будет работать. Кроме того, если ваши данные содержат &quot;, то они будут преобразованы в «что может или не может быть желательным.

1 голос
/ 10 декабря 2010

Я согласен с Кайлом в том, что ваша строка, вероятно, не соответствует.

Вместо первого шага Кайла вы можете использовать

string[] vals = Regex.Split(value, @"\s*\"",\s*");
1 голос
/ 10 декабря 2010

Есть много способов сделать это.Один неэффективный способ, который будет работать:

  1. Преобразование \ ", \" в табуляцию или какой-либо другой разделитель (я полагаю, вы пропустили несколько \ "в вашем примере, потому что в противном случае строка не согласована
  2. Снять все оставшиеся запятые
  3. Снять все оставшиеся \ "
  4. Преобразовать разделитель (например, табуляцию) обратно в запятую

Теперь у вас естьВы хотели в первую очередь

0 голосов
/ 10 декабря 2010

Вы можете попытаться использовать немного LINQ:

string excelData = "\\\" 1,234,123.00 \\\",\\\" 2,345.00 \\\", 342.00 ,\\\" 12,345.00 \\\"";

IEnumerable<string> cells = from x in excelData.Split(new string[] { "\\\"" }, StringSplitOptions.RemoveEmptyEntries)
                            let y = x.Trim(',').Trim()
                            where !string.IsNullOrWhiteSpace(y)
                            select y;

В качестве альтернативы, если вам не нравится это предложение, попробуйте реализовать аналогичный шаблон с RegEx.

0 голосов
/ 10 декабря 2010

Из вашего входного примера мы видим, что есть три «нежелательные» последовательности символов:

\"
\",
,\"

Итак, добавьте все эти последовательности во входной массив для метода Split:

string[] result = clipData.Split(new[] { @",\""", @"\"",", @"\""" }, 
    StringSplitOptions.None);

Это даст вам массив, содержащий несколько пустых элементов.Если это проблема, используйте StringSplitOptions.RemoveEmptyEntries вместо StringSplitOptions.None:

string[] result = clipData.Split(new[] { @",\""", @"\"",", @"\""" }, 
    StringSplitOptions.RemoveEmptyEntries);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...