Используя Java Streams API, следующее может работать, если вы можете гарантировать, что FIELD_TERMINATOR
не используется ни в STRING_DELIMITER
, ни в любом из ваших значений.
Path source = Paths.get("Your File");
char terminator = ',';
String delimiter = "|XYZ|";
String[][] parsed = Files.lines(source).map(l->
Stream.of(l.split(""+terminator)).map(s->
s.matches(delimiter+".*"+delimiter)?s.substring(delimiter.length(),s.length()-delimiter.length()):s
).toArray(String[]::new)
).toArray(String[][]::new);
Это решение разбивает каждую строку на свои поля и проверяет, окружено ли какое-либо заданное значение вашим разделителем, и соответственно удаляет его.
Редактировать:
Для многострочных данных я написал небольшой класс, который на основе Predicate<String[]>
решает, завершена ли строка данных.
package com.example.parser;
import java.util.stream.*;
import java.nio.file.*;
import java.io.IOException;
import java.util.*;
import java.util.function.*;
public class FileIterator implements Iterator<String> {
private String terminator;
private Predicate<String[]> complete;
private Iterator<String> source;
private String[] buffer;
private int pointer;
public FileIterator(Iterator<String> source, String terminator, Predicate<String[]> complete) {
this.source = source;
this.terminator = terminator;
this.complete = complete;
}
public static FileIterator from(Path path, String terminator, Predicate<String[]> complete) throws IOException {
return new FileIterator(Files.lines(path).iterator(),terminator,complete);
}
public Stream<String> asStream() {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(this, Spliterator.DISTINCT), false);
}
@Override
public boolean hasNext() {
return source.hasNext() || pointer < len(buffer);
}
@Override
public String next() {
if(pointer < len(buffer)) {
return buffer[pointer++];
} else {
buffer = source.next().split(terminator);
while(!complete.test(buffer)) {
buffer = concat(buffer,source.next().split(terminator));
}
pointer = 1;
return buffer[0];
}
}
private static String[] concat(String[] b1, String[] b2) {
if(b1 == null) return b2;
if(b2 == null) return b1;
String[] r = new String[b1.length+b2.length-1];
for(int i = 0; i < r.length; i++) {
if(i < b1.length-1) r[i] = b1[i];
else if(i == b1.length-1) r[i] = b1[i] + '\n' + b2[0];
else r[i] = b2[i-b1.length+1];
}
return r;
}
private static int len(String[] b) {
return b == null ? 0 : b.length;
}
}
Метод next()
работает путем создания буфера элементов текущей строки, повторно запрашивая предикат о том, закончен он или нет, а затем очищая его при последовательных вызовах. Предполагаемый вариант использования выглядит следующим образом:
FileIterator.from(Paths.get("yourFile"),",",(s)->yourWayOfDeterminingWetherARowIsTerminated(s)).asStream();
Элементы, разделенные новой строкой, также соединяются с помощью символа \n. Однако этот метод не удаляет строковые кавычки, но это можно сделать аналогичным образом, как описано выше. Также элементы возвращаются по отдельности, но реализация может быть изменена, чтобы возвращать весь буфер, чтобы соответствовать приведенному выше примеру. Чтобы проверить, завершена ли ваша строка, я предлагаю посмотреть регулярное выражение, которое идентифицирует ваш незавершенный адрес.
@Override
public String[] next() {
String[] buffer = source.next().split(terminator);
while(!complete.test(buffer)) {
buffer = concat(buffer,source.next().split(terminator));
}
return buffer;
}
person
Severin Nitsche
schedule
08.07.2020