Включить точку в предложении - регулярное выражение

У меня 40 000 строк, и мне нужно разделить каждую строку на разные предложения. Теперь я использую шаблон так:

String patternStr2 = "\\s*[\"']?\\s*([A-Z0-9].*?[\\.\\?!]\\s)['\"]?\\s*";

Он может обрабатывать почти все предложения, но для таких предложений: ВМС США, Первая мировая война будет разделена на 2 части: США и ВМС, Первая мировая война.

Есть ли решение для решения этой проблемы?

3 ответа

Решение

String patternStr2 = "(?<!\\..)(?<![A-Z].)[\\.\\?!](?!.\\.)"; затем с помощью метода java Matcher find() можно получить все предложения.

Почему вы пытаетесь соответствовать, пока вы хотите разделить?

Используйте следующее регулярное выражение:

(?<!\..)\.(?!.\.)

Объяснение:

  1. (?<!\..): Отрицательный взгляд за спиной, проверьте, нет ли сзади 2 символов.

  2. \.: Сопоставить точку.

  3. (?!.\.): Отрицательный взгляд вперед, проверьте, нет ли впереди 2 символов.

Онлайн демо

Примечание: не уверен, как это сделать в JAVA, но я думаю, что вы должны попробовать (?<!\\..)\\.(?!.\\.), Также не забудьте добавить точку к вашим расщепленным предложениям.

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

Если это трудно понять, дайте мне знать, и я добавлю несколько комментариев...

package test;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    private static final Pattern SENTENCE_DELIMITER = 
            Pattern.compile("((.+?)((?<!\\.[A-Z])(\\.\\s)(.+))?)");
    public static void main(String[] args) {
        String lineWithOneSentence = 
                "U.S. Navy, World War I";
        String lineWithTwoSentences = 
                "U.S. Navy, World War I. U.S. Air Force, World War III.";
        Matcher matcher = SENTENCE_DELIMITER.matcher(lineWithOneSentence);
        if (matcher.matches()) {
            for (int i = 0; i <= matcher.groupCount(); i++) {
                switch (i) {
                case 0: 
                    System.out.println("WHOLE MATCH: " + matcher.group(i));
                    break;
                case 2: 
                    System.out.println("FIRST SENTENCE: "+ matcher.group(i));
                    break;
                case 5: 
                    System.out.println("SECOND SENTENCE: " + matcher.group(i));
                default:
                }

            }
        }
        matcher = SENTENCE_DELIMITER.matcher(lineWithTwoSentences);
        if (matcher.matches()) {
            for (int i = 0; i <= matcher.groupCount(); i++) {
                switch (i) {
                case 0: 
                    System.out.println("WHOLE MATCH: " + matcher.group(i));
                    break;
                case 2: 
                    System.out.println("FIRST SENTENCE: "+ matcher.group(i));
                    break;
                case 5: 
                    System.out.println("SECOND SENTENCE: " + matcher.group(i));
                default:
                }
            }
        }
    }
}

Обходной путь здесь заключается в следующем:

  • Используйте группы
  • Используйте отрицательный вид сзади для точек, за которыми следует пробел, чтобы убедиться, что им не предшествует точка, за которой следует заглавная буква (как в "U *.S*._").

Это довольно излишне и, вероятно, будет проблемой в какой-то момент, например, если ваш текст не является последовательным в соответствии с пунктуацией.


Ouput:

WHOLE MATCH: U.S. Navy, World War I
FIRST SENTENCE: U.S. Navy, World War I
SECOND SENTENCE: null
WHOLE MATCH: U.S. Navy, World War I. U.S. Air Force, World War III.
FIRST SENTENCE: U.S. Navy, World War I
SECOND SENTENCE: U.S. Air Force, World War III.
Другие вопросы по тегам