Анализ входных данных CSV с помощью регулярного выражения в java

StackOverflow https://stackoverflow.com/questions/1441556

  •  10-07-2019
  •  | 
  •  

Вопрос

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

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

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"

Что я упускаю из виду?

Это было полезно?

Решение

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

Попробуй:

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

Другие советы

(?:^|,)\s*(?:(?:(?=")"([^"].*?)")|(?:(?!")(.*?)))(?=,|$)

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

Объяснение:

(?:^|,)\s*

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

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

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

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

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

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

(?=,|$)

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

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

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);
        }
    }

}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top