2017-01-25 6 views
0

Я пытаюсь разобрать текстовый файл, который имеет серию «записей», которые начинаются с числа (за которым следует NBSP и 1-2 пробела), содержат несколько сотен символов букв и цифр, разрывы строк строки, но дон В конце концов ничего предсказуемого. Единственный способ определить конец записи, чтобы попасть в следующий экземпляре стартовых маркеров, который может соответствовать следующему регулярному выражению:Разделить на регулярное выражение и захватить согласованное выражение-разделитель в Java?

\\d{1,4}\\u00A0\\s+ 

Содержание было рука вошла с непредсказуемыми разрывами строк, так что я убрал их. Это оставляет меня со шнуром.

1 blah blah blah 2 blah blah blah ... 875 blah blah blah 

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

Этот вопрос (Java String Regex split and capture splitted portion) кажется похожим, но спрашивающий знает, где заканчивается каждый фрагмент текста; тогда как я знаю только, где все начинается.

Так есть альтернативный способ разделить, но сохранить текстовое совпадение с помощью регулярного выражения split?

Благодаря

ответ

2

Если вы хотите просто проверить, если после вашего текста какой-либо другой текст, существует, но не в том числе другой текст в игре (например, проверка, если после foo является bar, но без включения bar в матче), то вы ищете look-around mechanism или, точнее, положительный взгляд вперед (?=...).

Так что давайте начнем с split("(?=\\d{1,4}\\u00A0\\s+)"). Это будет разделяться до любой серии из 1-4 цифр, которые имеют NBSP после нее и некоторые пробелы. Проблема с этим состоит в том, что для текста как

1234[nbsp]___ 

это описывает места (отмеченные |)

|1234[nbsp]___ 
1|234[nbsp]___ 
12|34[nbsp]___ 
123|4[nbsp]___ 

Но мы не хотим, чтобы расщепление между цифрами. Мы должны добавить условие для предотвращения такого разделения. Так что было бы неплохо, если бы мы могли сказать «не может быть цифры до места раскола». Для этого мы можем использовать негативный внешний вид за (?<!...) который в нашем случае будет выглядеть как (?<!\\d).

Так окончательное решение может выглядеть как:

split("(?<!\\d)(?=\\d{1,4}\\u00A0\\s+)") 
+0

Ах. Очень хорошо. Для потомков: этот метод разделения позволил мне сохранить динамический разделитель, соответствующий регулярному выражению в каждой раздвоенной линии. – user2029783

2

Не используйте split(), но написать свой собственный цикл регулярных выражений, например

String input = "...your input..."; 
Matcher m = Pattern.compile("\\d{1,4}\\u00A0\\s+").matcher(input); 
int prev = 0; 
while (m.find()) { 
    String prevText = input.substring(prev, m.start()); 
    prev = m.end(); 
    String delimiter = m.group(); 
    // ... code here ... 
} 
String tailText = input.substring(prev); // text after last delimiter 
// ... code here ... 
+0

вариант:.? 'Pattern.compile (" (*) (\\ d {1,4} \\ u00A0 \\ S +) ", Pattern.DOTALL); while (m.find()) {String prevText = m.group (1); Строковый разделитель = m.group (2); ...} '. Или, если вы заботитесь о неиспользуемом бите в конце: 'String delimiter; Pattern.compile ("(. *?) (\\ d {1,4} \\ u00A0 \\ s + | $)", Pattern.DOTALL); while (! "" .equals (разделитель)) {m.find(); String prevText = m.group (1); delimiter = m.group (2); ...} '. –

+0

@DavidKnipe Первая часть бесполезна, потому что вы определенно заботитесь о хвостовом тексте, учитывая, что разделитель является префиксом, а не терминатором. --- Для второй части вы просто вызвали 'IllegalStateException', потому что это происходит при вызове [' group() '] (https://docs.oracle.com/javase/8/docs/api/java/util /regex/Matcher.html#group-int-) после 'find()' возвращает false. Говорит так прямо в джавадоке. --- Ну, я имею в виду, вот что произойдет после того, как каким-то образом будет исправлена ​​ошибка компиляции 'delimiter', которая не инициализируется. – Andreas

+0

'find()' не должен возвращать значение false, потому что я добавил '| $' в регулярное выражение, поэтому он должен совпадать в конце без разделителя. И измените 'String delimiter;' на 'String delimiter = null;'. –