Разбор CSV-ввода с помощью RegEx в Java - PullRequest
16 голосов
/ 18 сентября 2009

Я знаю, теперь у меня две проблемы. Но мне весело!

Я начал с этого совета не пытаться разделить, а вместо этого найти подходящее поле и расширил его до этого выражения.

final Pattern pattern = Pattern.compile("\"([^\"]*)\"|(?<=,|^)([^,]*)(?=,|$)");

Выражение выглядит так без раздражающих кавычек:

"([^"]*)"|(?<=,|^)([^,]*)(?=,|$)

Это хорошо работает для меня - либо соответствует "двум кавычкам и тому, что между ними", либо "что-то между началом строки или запятой и концом строки или запятой". Перебор совпадений возвращает мне все поля, даже если они пусты. Например,

the quick, "brown, fox jumps", over, "the",,"lazy dog"

разбивается на

the quick
"brown, fox jumps"
over
"the"

"lazy dog"

Отлично! Теперь я хочу отбросить кавычки, поэтому я добавил заглядывающие и заглядывающие группы, которые не захватывали, как я делал для запятых.

final Pattern pattern = Pattern.compile("(?<=\")([^\"]*)(?=\")|(?<=,|^)([^,]*)(?=,|$)");

снова выражение:

(?<=")([^"]*)(?=")|(?<=,|^)([^,]*)(?=,|$)

Вместо желаемого результата

the quick
brown, fox jumps
over
the

lazy dog

теперь я получаю эту разбивку:

the quick
"brown
 fox jumps"
,over,
"the"
,,
"lazy dog"

Чего мне не хватает?

Ответы [ 4 ]

8 голосов
/ 18 сентября 2009

Приоритет оператора. В основном нет. Это все слева направо. Таким образом, or (|) применяется к заглядыванию в конец закрывающей кавычки и к запятому

Попытка:

(?:(?<=")([^"]*)(?="))|(?<=,|^)([^,]*)(?=,|$)
6 голосов
/ 30 декабря 2015
(?:^|,)\s*(?:(?:(?=")"([^"].*?)")|(?:(?!")(.*?)))(?=,|$)

Это должно делать то, что вы хотите.

Пояснение:

(?:^|,)\s*

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

Посмотрите вперед и посмотрите, начинается ли все остальное с цитаты

(?:(?=")"([^"].*?)")

Если это так, то сопоставлять без жадности до следующей цитаты.

(?:(?!")(.*?))

Если он не начинается с кавычки, сопоставляйте его без жадности до следующей запятой или конца строки.

(?=,|$)

Шаблон должен заканчиваться запятой или концом строки.

4 голосов
/ 18 сентября 2009

Когда я начал понимать, что я сделал неправильно, я также начал понимать, насколько запутанными выглядят обходные пути. Я наконец понял, что мне не нужен весь подобранный текст, я хотел, чтобы в нем были определенные группы. В итоге я использовал что-то очень похожее на мой исходный RegEx, за исключением того, что я не заглядывал в конец запятой, что, по-моему, должно быть немного более эффективным. Вот мой окончательный код.

package regex.parser;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CSVParser {

    /*
     * This Pattern will match on either quoted text or text between commas, including
     * whitespace, and accounting for beginning and end of line.
     */
    private final Pattern csvPattern = Pattern.compile("\"([^\"]*)\"|(?<=,|^)([^,]*)(?:,|$)");  
    private ArrayList<String> allMatches = null;    
    private Matcher matcher = null;
    private String match = null;
    private int size;

    public CSVParser() {        
        allMatches = new ArrayList<String>();
        matcher = null;
        match = null;
    }

    public String[] parse(String csvLine) {
        matcher = csvPattern.matcher(csvLine);
        allMatches.clear();
        String match;
        while (matcher.find()) {
            match = matcher.group(1);
            if (match!=null) {
                allMatches.add(match);
            }
            else {
                allMatches.add(matcher.group(2));
            }
        }

        size = allMatches.size();       
        if (size > 0) {
            return allMatches.toArray(new String[size]);
        }
        else {
            return new String[0];
        }           
    }   

    public static void main(String[] args) {        
        String lineinput = "the quick,\"brown, fox jumps\",over,\"the\",,\"lazy dog\"";

        CSVParser myCSV = new CSVParser();
        System.out.println("Testing CSVParser with: \n " + lineinput);
        for (String s : myCSV.parse(lineinput)) {
            System.out.println(s);
        }
    }

}
2 голосов
/ 18 сентября 2009

Я знаю, что это не то, что хочет OP, но для других читателей, один из методов String.replace может быть использован для удаления кавычек из каждого элемента в массиве результатов текущего регулярного выражения OP.

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