Спасибо @JosepValls за отличную идею.
Вот несколько примеров кода, как я упрощаю предложения с 3 или более однородными словами.
Прежде всего, я определил несколько регулярных выражений для случаев
jj(optional) nn, jj(optional) nn, jj(optional) nn and jj(optional) nn
jj(optional) nn, jj(optional) nn, jj(optional) nn , jj(optional) nn ...
jj , jj , jj
jj , jj and jj
vb nn(optional) , vb nn(optional) , vb nn(optional)
and so on
регулярные выражения
Pattern nounAdjPattern = Pattern.compile("(((jj)\\s(nn)|(jj)|(nn))\\s((cc)|,)\\s){2,}((jj)\\s(nn)|(jj)|(nn))");
Pattern verbPatter = Pattern.compile("((vb\\snn|vb)\\s((cc)|,)\\s){2,}((vb\\snn)|vb)");
Этот шаблон будет использоваться для определения, имеет ли входное предложение список однородных слов или нет, и для нахождения границ. После этого я создаю список POS на основе слов из оригинального предложения
final Sentence parsed = new Sentence(sentence);
final List<String> words = parsed.words();
List<String> pos = parsed.posTags().stream()
.map(tag -> tag.length() < 2 ? tag.toLowerCase() : tag.substring(0, 2).toLowerCase())
.collect(Collectors.toList());
Чтобы сопоставить эту структуру POS с регулярными выражениями - список совпадений со строкой
String posString = pos.stream().collect(Collectors.joining(" "));
Если предложение не соответствует ни одному регулярному выражению - давайте вернем ту же строку другим способом - давайте упростим его.
if (!matcher.find()) {
return new SimplificationResult(Collections.singleton(sentence));
}
return new SimplificationResult(simplify(posString, matcher, words));
В упрощенном методе я ищу границы однородной части и извлекаю из списка слов 3 часть - начало и конец, которая не изменится, и однородную часть, которая будет выведена в части. И после получения однородной части на части - я строю несколько упрощенных предложений, таких как начало + кусок + конец.
private Set<String> simplify(String posString, Matcher matcher, List<String> words) {
String startPOS = posString.substring(0, matcher.start());
String endPPOS = posString.substring(matcher.end());
int wordsBeforeCnt = StringUtils.isEmpty(startPOS) ? 0 : startPOS.trim().split("\\s+").length;
int wordsAfterCnt = StringUtils.isEmpty(endPPOS) ? 0 : endPPOS.trim().split("\\s+").length;
String wordsBefore = words.subList(0, wordsBeforeCnt)
.stream()
.collect(Collectors.joining(" "));
String wordsAfter = words.subList(words.size() - wordsAfterCnt, words.size())
.stream()
.collect(Collectors.joining(" "));
List<String> homogeneousPart = words.subList(wordsBeforeCnt, words.size() - wordsAfterCnt);
Set<String> splitWords = new HashSet<>(Arrays.asList(",", "and"));
Set<String> simplifiedSentences = new HashSet<>();
StringBuilder sb = new StringBuilder(wordsBefore);
for (int i = 0; i < homogeneousPart.size(); i++) {
String part = homogeneousPart.get(i);
if (!splitWords.contains(part)) {
sb.append(" ").append(part);
if (i == homogeneousPart.size() - 1) {
sb.append(" ").append(wordsAfter).append(" ");
simplifiedSentences.add(sb.toString());
}
} else {
sb.append(" ").append(wordsAfter).append(" ");
simplifiedSentences.add(sb.toString());
sb = new StringBuilder(wordsBefore);
}
}
return simplifiedSentences;
Так, например предложение
I love and kiss and adore my beautiful mom, clever dad and sister.
будет упрощено до 9 предложений, если мы будем использовать 2 регулярных выражения выше
I adore my clever dad .
I love my clever dad .
I love my sister .
I kiss my sister .
I kiss my clever dad .
I adore my sister .
I love my beautiful mom .
I adore my beautiful mom .
I kiss my beautiful mom .
Этот код работает только с 3 или более однородными словами, потому что для 2 слов существует множество исключений. Э.Г.
Cat eats mouse, dog eats meat.
Таким образом, предложение не может быть упрощено.