Разбор строки, содержащей экранированные символы, с использованием Java - PullRequest
5 голосов
/ 10 мая 2009


Интересно, может ли кто-нибудь помочь мне разобраться, как разобрать строку, имеющую следующий формат:

;field1-field2-fieldN;field1-field2-fieldN;

Каждая запись отделяется символом ';' и каждое поле в записи разделено символом «-». Сложность состоит в том, что отдельные поля могут содержать экранированные символы-разделители, такие как "\;" или же "-". Это приводит к сбою моего простого кода разбора ниже. Поэтому я пытаюсь придумать выражения регулярных выражений, которые будут соответствовать разделителям, но не совпадать с экранированными разделителями. Мое знание регулярных выражений не так уж велико, но я ожидал, что должен быть способ объединить "([^ \;])" и "([;])", чтобы получить то, что мне нужно.

public static List<ParsedRecord> parse(String data) {
    List<ParsedRecord> parsedRecords = new List<ParsedRecord>();
    String[] records = data.split(";");
    for (String record : records) {
        String[] fields = data.split("-");
        parsedRecords.add(new parsedRecord(fields));
    }
    return parsedRecords;
}

Заранее большое спасибо.

Ответы [ 2 ]

7 голосов
/ 10 мая 2009

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

split("[^\\];")

Чтобы разделить на что-нибудь, что является ";" но не если до этого есть "\". И то же самое для тире:

split("[^\\]-")
7 голосов
/ 10 мая 2009

Скорее всего, вам лучше всего делать эскапинг и расщепление в одном проходе. Я знаю, что это неправильно с точки зрения разделения двух отдельных частей функциональности, но он избегает некоторых неловких угловых случаев (например, представьте «foo \; bar», где; следует за обратной косой чертой, но все еще является разделителем).

Вот некоторый чрезвычайно упрощенный код для анализа - он предполагает, что любая обратная косая черта в основном означает «обрабатывать следующий символ как простой ввод», но это все.

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        List<String> parsed = parse(args[0]);
        for (String x : parsed)
        {
            System.out.println(x);
        }
    }

    public static List<String> parse(String text)
    {
        List<String> ret = new ArrayList<String>();
        StringBuilder current = new StringBuilder();
        boolean escaping = false;

        for (int i=0; i < text.length(); i++)
        {
            char c = text.charAt(i);
            if (escaping)
            {
                current.append(c);
                escaping = false;
            }
            else
            {
                if (c == '\\')
                {
                    escaping = true;
                }
                else if (c == ';')
                {
                    ret.add(current.toString());
                    current = new StringBuilder();
                }
                else
                {
                    current.append(c);
                }
            }
        }
        if (escaping)
        {
            throw new IllegalArgumentException("Ended in escape sequence");
        }
        ret.add(current.toString());
        return ret;
    }
}

(Обратите внимание, что это не делает бизнес для разделения каждой записи на несколько полей, но вам просто нужно изменить то, что вы делаете с помощью ';', а также реагировать на '-' - принцип тот же. )

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