Java - регулярное выражение для разделения токенов с минимальным размером и разделителями

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

Я хочу разделить строку в Java, и у меня есть 4 ограничения:

  1. Разделителями являются [.?!] (Конец предложения)
  2. Десятичные числа не должны быть токенизированы
  3. Разделители не должны быть удалены.
  4. Минимальный размер каждого токена должен быть 5

Например, для ввода:

"Hello World! This answer worth $1.45 in U.S. dollar. Thank you."

Выход будет:

[Hello World!, This answer worth $1.45 in U.S. dollar., Thank you.]

До сих пор я получил ответ на три первых ограничения этого регулярного выражения:

text.split("(?<=[.!?])(?<!\\d)(?!\\d)");

И я знаю, что я должен использовать {5,} где-то в моем регулярном выражении, но любая комбинация, которую я пробовал, не работает.

Для таких случаев, как: "I love U.S. How about you?" не имеет значения, если он дает мне одно или два предложения, поскольку это не токенизирует S. как отдельное предложение.

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

ОБНОВЛЕНИЕ: Как отметил Chris Bode в комментариях, почти невозможно решить подобные вопросы (чтобы охватить все случаи, происходящие на естественных языках) с помощью регулярных выражений. Тем не менее, я нашел ответ HamZa шкафу, и самый полезный.

Так что будьте осторожны! Принятый ответ не охватывает все возможные варианты использования!

2 ответа

Решение

Основываясь на моем ответе из ранее сделанного регулярного выражения.
Регулярное выражение было в основном (?<=[.?!])\s+(?=[a-z]) что означает совпадение с любым пробелом один или несколько раз, которому предшествует либо ., ? или же ! и затем [a-z] (не забывая i модификатор).

Теперь давайте изменим это в соответствии с потребностями этого вопроса:

  1. Сначала мы преобразуем его в регулярное выражение JAVA: (?<=[.?!])\\s+(?=[a-z])
  2. Мы добавим i модификатор для соответствия без учета регистра (?i)(?<=[.?!])\\s+(?=[a-z])
  3. Мы положим выражение в позитивную перспективу, чтобы не "съесть" символы (в данном случае разделители): (?=(?i)(?<=[.?!])\\s+(?=[a-z]))
  4. Мы добавим отрицательный вид сзади, чтобы проверить, нет ли сокращения в формате LETTER DOT LETTER DOT: (?i)(?<=[.?!])(?<![a-z]\.[a-z]\.)\\s+(?=[a-z])

Итак, наше последнее выражение выглядит так: (?i)(?<=[.?!])(?<![a-z]\.[a-z]\.)\\s+(?=[a-z]),

Некоторые ссылки:

Как насчет следующего регулярного выражения?

(?<=[.!?])(?!\w{1,5})(?<!\d)(?!\d)

например

private static final Pattern REGEX_PATTERN = 
        Pattern.compile("(?<=[.!?])(?!\\w{1,5})(?<!\\d)(?!\\d)");

public static void main(String[] args) {
    String input = "Hello World! This answer worth $1.45 in U.S. dollar. Thank you.";

    System.out.println(java.util.Arrays.toString(
        REGEX_PATTERN.split(input)
    )); // prints "[Hello World!,  This answer worth $1.45 in U.S.,  dollar.,  Thank you.]"
}
Другие вопросы по тегам