Разделение строки через запятую, игнорирование запятых в кавычках, но разрешение строк с одной двойной кавычкой - PullRequest
1 голос
/ 11 мая 2011

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

IE. Нужно "test05, \"test, 05\", test\", test 05", чтобы разбить на

  • test05
  • "test, 05"
  • test"
  • test 05

Я пробовал метод, подобный тому, который упоминался здесь:

Регулярное выражение для разбиения строки с использованием пробела, если оно не заключено в одинарные или двойные кавычки

Использование Matcher вместо split(). однако, что конкретные примеры он разделяет на пробелы, а не на запятые. Вместо этого я попытался настроить шаблон для учета запятых, но мне не повезло.

String str = "test05, \"test, 05\", test\", test 05";
str = str + " "; // add trailing space
int len = str.length();
Matcher m = Pattern.compile("((\"[^\"]+?\")|([^,]+?)),++").matcher(str);

for (int i = 0; i < len; i++)
{
    m.region(i, len);

    if (m.lookingAt())
    {
        String s = m.group(1);

        if ((s.startsWith("\"") && s.endsWith("\"")))
        {
            s = s.substring(1, s.length() - 1);
        }

        System.out.println(i + ": \"" + s + "\"");
        i += (m.group(0).length() - 1);
    }
}

Ответы [ 5 ]

1 голос
/ 06 мая 2015

У меня были похожие проблемы с этим, и я не нашел хорошего решения .net, поэтому пошел своими руками.

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

Итак, я написал функцию, которая игнорирует запятые в двойных кавычках. это происходит путем преобразования входной строки в массив символов и синтаксического анализа символа char

public static string[] Splitter_IgnoreQuotes(string stringToSplit)
    {   
        char[] CharsOfData = stringToSplit.ToCharArray();
        //enter your expected array size here or alloc.
        string[] dataArray = new string[37];
        int arrayIndex = 0;
        bool DoubleQuotesJustSeen = false;          
        foreach (char theChar in CharsOfData)
        {
            //did we just see double quotes, and no command? dont split then. you could make ',' a variable for your split parameters I'm working with a csv.
            if ((theChar != ',' || DoubleQuotesJustSeen) && theChar != '"')
            {
                dataArray[arrayIndex] = dataArray[arrayIndex] + theChar;
            }
            else if (theChar == '"')
            {
                if (DoubleQuotesJustSeen)
                {
                    DoubleQuotesJustSeen = false;
                }
                else
                {
                    DoubleQuotesJustSeen = true;
                }
            }
            else if (theChar == ',' && !DoubleQuotesJustSeen)
            {
                arrayIndex++;
            }
        }
        return dataArray;
    }

Эта функция, на мой вкус приложения, также игнорирует ("") на любом входе, поскольку они не нужны и присутствуют на моем входе.

1 голос
/ 11 мая 2011

Вы достигли точки, где регулярные выражения ломаются.

Я бы порекомендовал вам написать простой разделитель, который обрабатывает ваши особые случаи как вы .Test Driven Development отлично подходит для этого.

Похоже, однако, что вы пытаетесь проанализировать линии CSV.Рассматривали ли вы использование CSV-библиотеки для этого?

0 голосов
/ 12 мая 2011

Попробуйте это:

import java.util.regex.*;

public class Main {
  public static void main(String[] args) throws Exception {

    String text = "test05, \"test, 05\", test\", test 05";

    Pattern p = Pattern.compile(
        "(?x)          # enable comments                                      \n" +
        "(\"[^\"]*\")  # quoted data, and store in group #1                   \n" +
        "|             # OR                                                   \n" +
        "([^,]+)       # one or more chars other than ',', and store it in #2 \n" +
        "|             # OR                                                   \n" +
        "\\s*,\\s*     # a ',' optionally surrounded by space-chars           \n"
    );

    Matcher m = p.matcher(text);

    while (m.find()) {
      // get the match
      String matched = m.group().trim();

      // only print the match if it's group #1 or #2
      if(m.group(1) != null || m.group(2) != null) {
        System.out.println(matched);
      }
    }
  }
}

Для test05, "test, 05", test", test 05 он производит:

test05
"test, 05"
test"
test 05

и для test05, "test 05", test", test 05 он производит:

test05
"test 05"
test"
test 05
0 голосов
/ 12 мая 2011

Если вам не нужно заниматься DIY, вам следует рассмотреть класс Apache Commons org.apache.commons.csv.CSVParser

http://commons.apache.org/sandbox/csv/apidocs/org/apache/commons/csv/CSVParser.html

0 голосов
/ 11 мая 2011

Разделить по этому шаблону:

(?<=\"?),(?!\")|(?<!\"),(?=\")

так будет:

String[] splitArray = subjectString.split("(?<=\"?),(?!\")|(?<!\"),(?=\")");

UPD: в соответствии с недавними изменениями в логике вопроса, лучше не использовать разделение по голымсначала следует отделить текст через запятую от текста без запятых, а затем выполнить простое разбиение (",") на последнем.Просто используйте простой цикл for и проверьте, сколько кавычек вы встретили, одновременно сохраняя прочитанные символы в StringBuffer.Сначала вы сохраняете свои символы в StringBuffer, пока не встретите кавычки, затем вы помещаете свой StringBuffer в массив, содержащий строки, которых не было в кавычках.Затем вы создаете новый StringBuffer и сохраняете следующие символы, которые вы читаете, после того, как вы встретили вторую запятую, вы останавливаете и помещаете свой новый StringBuffer в массив, содержащий строки, которые были в запятых.Повторяя до конца строки.Таким образом, у вас будет 2 массива, один со строками, которые были в запятых, другие со строками, не запятыми.Затем вы должны разделить все элементы второго массива.

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