Как сказал Джефф Холт в комментарии : «Посмотрите на Pattern.quote()
»:
[...] создает строку, которая может использоваться для создания шаблона, который будет соответствовать строке s
, как если бы это был буквальный шаблон.
Метасимволам или escape-последовательностям во входной последовательности не будет придано никакого специального значения.
Регулярное выражение в вопросе использует [^.!?]*
, чтобы сопоставить любой символ в предложении, который не является символом конца предложения (.
, !
или ?
).
Однако мы хотим чтобы сопоставить полные предложения со специальными «словами», такими как i.e.
, e.g.
и etc.
, поэтому нам нужно увеличить это значение до (i.e.|e.g.|etc.|[^.!?])*
, за исключением того, что мы должны экранировать (\
) специальные символы регулярного выражения (например, .
) в этих специальных словах.
Мы можем использовать Pattern.quote()
для этого, а также для самого поискового слова.
public static List<String> findSentencesContaining(String fullText, String word, String[] specials) {
Pattern p = buildRegexToFindSentencesContaining(word, specials);
List<String> sentences = new ArrayList<>();
for (Matcher m = p.matcher(fullText); m.find(); )
sentences.add(m.group().replaceAll("\\s+", " ").trim()); // normalize group of whitespace into a single space
return sentences;
}
public static Pattern buildRegexToFindSentencesContaining(String word, String[] specials) {
StringJoiner regexText = new StringJoiner("|", "(?:", "|[^.!?])*").setEmptyValue("[^.!?]*");
for (String s : specials)
regexText.add(toWordRegex(s));
String regex = regexText + toWordRegex(word) + regexText + "[.!?]";
return Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
}
private static String toWordRegex(String word) {
String regex = Pattern.quote(word);
if (word.matches("\\b.*"))
regex = "\\b" + regex;
if (word.matches(".*\\b"))
regex = regex + "\\b";
return regex;
}
Тест
String fullText = "This is a test. We're testing that sentences\n" +
"can span multiple lines, i.e. that line" +
"terminators can appear in a sentence. We're\n" +
"also testing that sentences can contain\n" +
"special words containing sentence-ending\n" +
"\"words\", e.g. \"i.e.\" and \"etc.\". In\n" +
"addition, (special) word matching is\n" +
"case-insensitive.";
String[] specials = { "i.e.", "e.g.", "etc." };
for (String word : new String[] { "test", "also", "we're", "is", "happy" }) {
System.out.println("Sentences containing word \"" + word + "\":");
List<String> sentences = findSentencesContaining(fullText, word, specials);
if (sentences.isEmpty())
System.out.println(" ** NOT FOUND");
else {
for (String sentence : sentences)
System.out.println(" " + sentence);
}
}
Выход
Sentences containing word "test":
This is a test.
Sentences containing word "also":
We're also testing that sentences can contain special words containing sentence-ending "words", e.g. "i.e." and "etc.".
Sentences containing word "we're":
We're testing that sentences can span multiple lines, i.e. that lineterminators can appear in a sentence.
We're also testing that sentences can contain special words containing sentence-ending "words", e.g. "i.e." and "etc.".
Sentences containing word "is":
This is a test.
In addition, (special) word matching is case-insensitive.
Sentences containing word "happy":
** NOT FOUND