Java-разделитель при чтении текстового файла — регулярное выражение / или нет?

#java #regex #delimiter #text-files #separator

#java #регулярное выражение #разделитель #текстовые файлы #разделитель

Вопрос:

Я пытаюсь прочитать текстовый файл, написанный в этой форме:

     AB523:[joe, pierre][charlie][dogs,cat]
    ZZ883:[ronald, zigomarre][pele]
 

Я хотел бы создать свою структуру и правильно извлечь информацию.

AB523 — один
Джо, Пьер — один
Чарли — одни
собаки, кошка — один

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

У вас есть какое-либо решение? или предложение

Каково соглашение при записи в текстовый файл? Каковы наилучшие методы работы с разделителями?

РЕДАКТИРОВАТЬ: текстовый файл также генерируется мной, поэтому я контролирую общий шаблон. Какой наилучший шаблон вывода позволит уменьшить объем работы при его повторном чтении?

Ответ №1:

Я бы использовал здесь регулярные выражения, потому что, похоже, меньше кода для поддержки, и ваш язык, безусловно, регулярный. Вместе с java.util.Scanner экземпляром для большей эффективности. Вот некоторый код:

 import java.io.Reader;
import java.io.StringReader;
import java.util.Scanner;
import java.util.regex.Pattern;

public class ScannerTest {

private static final Pattern header = Pattern.compile("(.*):");
private static final Pattern names = Pattern.compile("\[([^\]] )\]");

public static void main(String[] args) {

    Reader reader = new StringReader(
            "AB523:[joe, pierre][charlie][dogs,cat]n"
                      "ZZ883:[ronald, zigomarre][pele]");

    Scanner scanner = new Scanner(reader);
    scanner.useDelimiter("n");

    while (scanner.hasNext()) {
        String h = scanner.findInLine(header);
        // Substring removes trailing ':'.
        System.out.println(h.substring(0, h.length() - 1));

        String n;
        while ((n = scanner.findInLine(names)) != null)
            // Substring removes '[' and ']'.
            System.out.println(n.substring(1, n.length() - 1));

        if (scanner.hasNext())
            scanner.nextLine();
    }
}
}
 

Тем не менее, мне все еще не удалось удалить вызовы подстрок, и, возможно, это скрывает некоторую неэффективность. Я предполагаю, что нет, из-за неизменности строк строки не должны воссоздаваться для этого случая.

РЕДАКТИРОВАТЬ: для повышения производительности я бы также рассмотрел ручной анализатор рекурсивного спуска.

Комментарии:

1. Я полностью понимаю, что вы там сделали. Почему-то мне интересно, лучшее ли это решение. Я добавил комментарий в свой оригинал post…to допустим, я также генерирую текстовый файл, чтобы я мог также изменить шаблон вывода.

2. Затем определите / используйте XML, вы найдете множество полезных API / инструментов.

Ответ №2:

Используйте String#split Pattern#split метод или. Например,

    String[] list ="AB523:[joe, pierre][charlie][dogs,cat]".split("[:\[\]] ");
   for(String s : list)
       System.out.println(s);
 

Комментарии:

1. Не могли бы вы, пожалуйста, объяснить мне свое регулярное выражение?

2. @user1023021: разделите входную строку, используя любой из разделителей ( : , [ , ] ) один или несколько раз.

Ответ №3:

Односимвольные разделители легко разделить: функция String.split() разделит символ или строку. Они делают именно то, что делает StringTokenizer, но делают это с более чистым синтаксисом. То есть String[] items = myString.split(",") выглядит намного чище, чем

 StringTokenizer st = new StringTokenizer(myString, ","); 
while(st.hasMoreTokens()){
    myList.add(st.nextToken();
}
 

( split Я говорю об использовании в будущем.)

Однако, похоже, что вы находитесь в немного более сложной ситуации, когда вам нужно получить материал, ограниченный слева [ и справа ] . Это требует регулярного выражения и захвата групп. Что-то вроде /[(.*)]/

CSV (значения, разделенные запятыми) являются общими для простых табличных данных, и формат даже до некоторой степени стандартизирован. Если вы хотите представлять более сложные объекты, вы можете использовать JSON или SOAP. Если вы используете хранилище только для Java, взгляните на встроенные функции сериализации Java.

Поскольку вы используете его локально и, вероятно, сохраняете какой-то объект Java для его представления, одним из способов было бы реализовать Serializable в любом объекте, представляющем ваши данные.

Если вам это не нравится, я бы выбрал JSON, потому что похоже, что вы делаете какую-то древовидную структуру.

Комментарии:

1. Спасибо за подсказку. Текстовый файл также генерируется мной, поэтому я контролирую общий шаблон. Какой наилучший шаблон вывода позволит уменьшить объем работы при его повторном чтении?

2. Я бы сказал, что это зависит от того, откуда вы получаете данные, но если у вас есть строго алфавитные строки, вы можете выбрать второй разделитель, например ; (например AB523:joe,pierre;charlie;dog,cat , etc).

3. Использование метода «split» для «AB523: джо, Пьер; Чарли; собака, кошка» не было бы лучшим решением в этом случае, верно? Я не вижу, как это было бы эффективно…

Ответ №4:

Поскольку у вас есть контроль над форматом файла, я бы предложил разделитель табуляции. Многие другие программы (например, Excel) будут читать разделители табуляции. Таким образом, файл будет выглядеть следующим образом (t представляет вкладку)

 AB523tjoe, pierretcharlietdogs,cat
ZZ883tronald, zigomarretpele
 

Примечание — Вы не можете использовать разделитель через запятую (CSV), другой распространенный формат, потому что запятая является допустимым значением в ваших строках. Аналогично, разделитель табуляции будет иметь проблемы, если символ табуляции является допустимым символом в ваших строках.

Как и другие, String.split() — хороший способ анализа файла.

Ответ №5:

Если вы создаете файл данных, создайте его в стандартном формате firmat, таком как CSV (для простых линейных данных) или Json (для структурированных данных) или даже XML (для интенсивной обработки структурированных данных).