package bg.bozho.ikratko.other; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.SortedMap; import javax.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; import org.apache.commons.collections4.trie.PatriciaTrie; import org.apache.commons.collections4.Trie; import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Service; import bg.bozho.ikratko.Checker; import bg.bozho.ikratko.Checker.InflectedFormType; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @Service @DependsOn("checker") public class RhymeService { private Trie<String, List<String>> reverse; private static char[] vowels = new char[] {'а', 'ъ', 'о', 'у', 'е', 'и', 'ю', 'я'}; @PostConstruct public void init() { reverse = new PatriciaTrie<>(); for (Entry<String, Checker.InflectedFormType> entry: Checker.formsDictionary.entrySet()) { //using a StringBuilder so that no entry is placed in the jvm string pool String key = new StringBuilder(entry.getKey()).reverse().substring(0, Math.min(5, entry.getKey().length())); List<String> list = reverse.get(key); if (list == null) { list = new ArrayList<String>(); reverse.put(key, list); } list.add(entry.getKey()); } } public Set<String> getRhymes(String ending, int syllables) { SortedMap<String, List<String>> reverseRhymes = reverse.prefixMap(StringUtils.reverse(ending)); Set<String> rhymes = Sets.newHashSetWithExpectedSize(reverseRhymes.size()); for (Entry<String, List<String>> reverseRhyme : reverseRhymes.entrySet()) { for (String word : reverseRhyme.getValue()) { // optionally limit the result to words with certain length if (syllables > 0 && getSyllables(word) != syllables) { continue; } rhymes.add(word); } } return rhymes; } public static void main(String[] args) { System.out.println(new RhymeService().getSyllables("лайно")); } private int getSyllables(String word) { int syllables = 0; for (int i = 0; i < word.length(); i++) { if (Arrays.binarySearch(vowels, word.charAt(i)) > -1) { syllables++; } } return syllables; } private static Map<Character, Character> similarReplacements = Maps.newHashMap(); static { Arrays.sort(vowels); similarReplacements.put('м', 'н'); similarReplacements.put('н', 'м'); similarReplacements.put('т', 'д'); similarReplacements.put('д', 'т'); similarReplacements.put('п', 'б'); similarReplacements.put('б', 'п'); similarReplacements.put('к', 'г'); similarReplacements.put('г', 'к'); similarReplacements.put('ш', 'ж'); similarReplacements.put('ж', 'ш'); similarReplacements.put('с', 'з'); similarReplacements.put('з', 'с'); similarReplacements.put('с', 'ш'); similarReplacements.put('ш', 'с'); similarReplacements.put('ж', 'з'); similarReplacements.put('з', 'ж'); similarReplacements.put('ф', 'в'); similarReplacements.put('в', 'ф'); } public Set<String> getSimilarEndings(String ending) { Set<String> similar = Sets.newHashSet(); for (int i = 0; i < ending.length(); i++) { Character replacement = similarReplacements.get(ending.charAt(i)); if (replacement != null) { similar.add(ending.replace(ending.charAt(i), replacement)); } } return similar; } }