Как включить завершающие пустые строки в Pattern.compile ("\\ R"). SplitAsStream (входная)? - PullRequest
0 голосов
/ 15 января 2019

Это не дублирование Разделение Java String удаляет пустые значения , что касается метода split(), возвращающего новый массив. В этом случае я бы хотел избежать массива .

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

Моя цель - обработать все строки, включая пустые строки, как показано в следующем примере:

String input = "foo\nbar\n\n\nzul\n\n\n";
Pattern NEWLINE = Pattern.compile("\\R");
int [] count = {1};
NEWLINE
    .splitAsStream(input)
    .forEach(line -> System.out.println(count[0]++ + ": " + line));

, который производит:

1: foo
2: baz
3: 
4: 
5: zul

Тем не менее, он отсутствует:

6: 
7:

Как включить последние пустые строки?

Ответы [ 3 ]

0 голосов
/ 15 января 2019

Вы можете использовать a lookahead (?=(\\R)), чтобы убедиться, что разделитель \\R не используется, а затем удалить его самостоятельно с помощью String.trim().

String input = "foo\nbar\n\n\nzul\n\n\n";
Pattern NEWLINE = Pattern.compile("(?=(\\R))");
int[] count = {1};
NEWLINE.splitAsStream(input)
       .map(String::trim)
       .forEach(line -> System.out.println(count[0]++ + ": " + line));

Однако это приведет к совпадению нулевой длины для "" после последнего \n.

1: foo
2: bar
3: 
4: 
5: zul
6: 
7: 
8: 
0 голосов
/ 15 января 2019

Поскольку java 9 on может использовать Matcher.results (), получая Stream<MatchResult>

Pattern.compile("(.*)\\R").matcher(input)
    .results(mr -> System.out.println(count[0]++ + ": " + mr.group(1)));

Это гарантирует, что последняя "строка" также имеет завершающий \n. «.... \ nabc» будет отбрасывать последний abc.

Для этого, я думаю, должно сработать следующее (примечание group()), использующее упущение и требующее в конце $ хотя бы одного символа ..

Pattern.compile(".*(?=\\R)|.$)").matcher(input)
    .results(mr -> System.out.println(count[0]++ + ": " + mr.group()));

Разделение с -1 и проверка последней записи кажутся немного более читабельными.

0 голосов
/ 15 января 2019

В качестве альтернативы вы можете сделать свою собственную реализацию эквивалентного метода splitAsStream(), который включает в себя завершающие пустые строки и все же избегает создания экземпляра массива , такого как:

static Stream<String> splitAsStream(Pattern p, CharSequence input) {
    Spliterator<String> iter = new Spliterators.AbstractSpliterator<String>(
        Long.MAX_VALUE,
        Spliterator.ORDERED | Spliterator.SIZED
    ) {
        int index = 0;
        final Matcher m = p.matcher(input);

        @Override
        public boolean tryAdvance(Consumer<? super String> action) {
            while(m.find()) {
                if (index != 0 || index != m.start() || m.start() != m.end()) {
                    action.accept(input.subSequence(index, m.start()).toString());
                    index = m.end();
                    return true;
                }
            }
            if(index < input.length()) {
                // Add remaining segment
                action.accept(input.subSequence(index, input.length()).toString());
                index = input.length();
                return true;
            } else {
                return false;
            }
        }
    };
    return StreamSupport.stream(iter, false);
}
...