package ru.lexmin.lexm_core.dto;
/**
* Класс для получения от пользователя введённой информации а виде текста (text)
* и процента понимания (percent)
*
*/
public class ReceivedText {
/**
* Версия
*/
private static final long serialVersionUID = 5716001583591230233L;
// текст, который ввёл пользователь
private String text;
// желаемый процент понимания текста пользователем
private int percent;
/**
* Пустой конструктор
*/
public ReceivedText() {
super();
}
/**
* Конструктор с параметрами
*
* @param text
* {@link String}
* @param percent
* int
*/
public ReceivedText(String text, int percent) {
super();
this.text = text;
this.percent = percent;
}
/**
* @return text {@link String}
*/
public String getText() {
return text;
}
/**
* Устанавливает параметр
*
* @param text
* text {@link String}
*/
public void setText(String text) {
this.text = text;
}
/**
* @return percent {@link int}
*/
public int getPercent() {
return percent;
}
/**
* Устанавливает параметр
*
* @param percent
* percent {@link int}
*/
public void setPercent(int percent) {
this.percent = percent;
}
}
package ru.lexmin.lexm_core.dto;
import java.util.HashMap;
import java.util.Map;
/**
* Класс для передачи рзультов обработки текста в виде: - количество слов в
* тексте - честота употребления каждого слова.
*
* Количество слов хранится в поле countOfWords (int) Частота употребления
* хранится в поле frequencyWords (Map<String, Integer>): - ключом является
* слово - значением частора употребления в тексте
*
* Поле receivedText - содержет ссылку на dto с текстом и процентом понимания.
*
*/
public class WordStat {
/**
* Версия
*/
private static final long serialVersionUID = -1211530860332682161L;
// ссылка на dto с исходным текстом и параметрами
private ReceivedText receivedText;
// кол-во слов в тексте, на который ссылка receivedText
private int countOfWords;
// статистика по часторе слов текста, на который ссылка receivedText,
// отфильтрованная с учётом процента понимания
private Map<String, Integer> frequencyWords;
/**
* Констркутор по умолчанию
*/
public WordStat() {
super();
}
/**
* Конструктор с параметрами
*
* @param receivedText
* @param countOfWords
* @param frequencyWords
*/
public WordStat(ReceivedText receivedText, int countOfWords, Map<String, Integer> frequencyWords) {
this.receivedText = receivedText;
this.countOfWords = countOfWords;
this.frequencyWords = frequencyWords;
}
/**
* Конструктор задаёт значение поля receivedText из передоваемого объекта.
* остальнве поля интциализируются значениями по умолчанию
*
* @param receivedText
*/
public WordStat(ReceivedText receivedText) {
this.receivedText = receivedText;
// инициализация остальных полей значениями по умолчинию
this.countOfWords = 0;
this.frequencyWords = new HashMap<String, Integer>();
}
/**
* @return receivedText {@link ReceivedText}
*/
public ReceivedText getReceivedText() {
return receivedText;
}
/**
* Устанавливает параметр
*
* @param receivedText
* receivedText {@link ReceivedText}
*/
public void setReceivedText(ReceivedText receivedText) {
this.receivedText = receivedText;
}
/**
* @return countOfWords {@link int}
*/
public int getCountOfWords() {
return countOfWords;
}
/**
* Устанавливает параметр
*
* @param countOfWords
* countOfWords {@link int}
*/
public void setCountOfWords(int countOfWords) {
this.countOfWords = countOfWords;
}
/**
* @return frequencyWords {@link Map<String,Integer>}
*/
public Map<String, Integer> getFrequencyWords() {
return frequencyWords;
}
/**
* Устанавливает параметр
*
* @param frequencyWords
* frequencyWords {@link Map<String,Integer>}
*/
public void setFrequencyWords(Map<String, Integer> frequencyWords) {
this.frequencyWords = frequencyWords;
}
}
package ru.lexmin.lexm_core;
import ru.lexmin.lexm_core.dto.ReceivedText;
import ru.lexmin.lexm_core.dto.WordStat;
/**
* Данный интерфейс описывает основной функционал анализа получаемого от
* пользователя текста
*
*/
public interface TextAnalyzer {
/**
* Мемод получает объект класса {@link WordStat}, заполненный данными,
* актуальными для передаваемого объекта {@link ReceivedText}
*
* @param receivedText
* {@link ReceivedText}
* @return возврашает заполненный {@link WordStat}
*/
public abstract WordStat getWordStat(ReceivedText receivedText);
}
package ru.lexmin.lexm_core;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import ru.lexmin.lexm_core.dto.ReceivedText;
import ru.lexmin.lexm_core.dto.WordStat;
/**
* Этот класс является реализацией интерфейса TextAnalyzer
*
*/
public class TextAnalyzerImp implements TextAnalyzer {
/* Константы */
private final int PERCENT_100 = 100;
private final int ONE_WORD = 1;
private final String SPACE = " ";
// регулярное выражение: все испольуемые апострофы
private final String ANY_APOSTROPHE = "[’]";
// применяемый, стандартный апостроф
private final String AVAILABLE_APOSTROPHE = "'";
// регулярное выражение: не маленькие латинские буквы, не пробел и не
// апостроф(')
private final String ONLY_LATIN_CHARACTERS = "[^a-z\\s']";
// регулярное выражение: пробелы, более двух подрят
private final String SPACES_MORE_ONE = "\\s{2,}";
/**
* Метод преобразует передаваемый текст в нижнеме регистру, производит
* фильтрацию текста. В тексте отсаются только латинские буквы, пробельные
* символы и верхний апостроф. Пробелы два и более подрят заменяются одним.
*
* @param text
* {@link String}
* @return отфильтрованный текст
*/
private String filterText(String text) {
String resultText = text.toLowerCase().replaceAll(ANY_APOSTROPHE, AVAILABLE_APOSTROPHE)
.replaceAll(ONLY_LATIN_CHARACTERS, SPACE).replaceAll(SPACES_MORE_ONE, SPACE);
return resultText;
}
/**
* Метод преобразует получаемый текст в Map<{слво}, {количество}>
*
* @param text
* {@link String}
* @return заполненный Map
*/
private Map<String, Integer> getWordsMap(String text) {
Map<String, Integer> wordsMap = new HashMap<String, Integer>();
String newWord = "";
Pattern patternWord = Pattern.compile("(?<word>[a-z']+)");
Matcher matcherWord = patternWord.matcher(text);
// поиск слов в тексте по паттерну
while (matcherWord.find()) {
newWord = matcherWord.group("word");
if (wordsMap.containsKey(newWord)) {
// если слово уже есть в Map то увеличиваеи его количество на 1
wordsMap.replace(newWord, wordsMap.get(newWord) + ONE_WORD);
} else {
// если слова в Map нет то добавляем его со значением 1
wordsMap.put(newWord, ONE_WORD);
}
}
return wordsMap;
}
/**
* Метод возвращает общее количество слов, суммируя частоту употребления
* слов в получаемом Map
*
* @param wordsMap
* {@link Map}
* @return общее количество слов в тексте, по которому составлен Map
*/
private int getCountOfWords(Map<String, Integer> wordsMap) {
int countOfWords = 0;
// считаем в цикле сумму значений для всех слов в Map
for (Integer value : wordsMap.values())
countOfWords += value;
return countOfWords;
}
/**
* Метод производит вычисление процентрого соотнашения аргумента
* numberXPercents от аргумента number100Percents
*
* @param number100Percents
* int
* @param numberXPercents
* int
* @return прочентное соотношение
*/
private int getPercent(int number100Percents, int numberXPercents) {
return (numberXPercents * PERCENT_100) / number100Percents;
}
/**
* Метод выполняет фильтрацию слов в массива, чтобы их количество покрывало
* заданный процент понимания текста
*
* @param wordsMap
* {@link Map}
* @param countOfWords
* int
* @param percent
* int
* @return возвращает отфильтрованный массив, элементы когорого
* отсорвированы по убывающей
*/
private Map<String, Integer> filterWordsMap(Map<String, Integer> wordsMap, int countOfWords, int percent) {
// LinkedHashMap - ассоциативный массив, который запоминает порядок
// добавления элементов
Map<String, Integer> resultMap = new LinkedHashMap<String, Integer>();
int sumPercentOfWords = 0;
// создаёт поток из Map с записями Entry<String, Integer>,
// отсортированными по убыванию
Stream<Entry<String, Integer>> streamWords = wordsMap.entrySet()
.stream().sorted(Map.Entry.comparingByValue(
(Integer value1, Integer value2) -> (
value1.equals(value2)) ? 0 : ((value1 < value2) ? 1 : -1)
)
);
// создаём итератор для обхода всех записей потока
Iterator<Entry<String, Integer>> iterator = streamWords.iterator();
// добавляем в resultMap каждую последующую запись из итератора, пока не
// будет тостигнут заданный процент понимания
while (iterator.hasNext() && (sumPercentOfWords < percent)) {
Entry<String, Integer> wordEntry = iterator.next();
resultMap.put(wordEntry.getKey(), wordEntry.getValue());
sumPercentOfWords += getPercent(countOfWords, wordEntry.getValue());
}
return resultMap;
}
/*
* (non-Javadoc)
*
* @see
* ru.lexmin.lexm_core.TextAnalyzer#getWordStat(ru.lexmin.lexm_core.dto.
* ReceivedText)
*/
@Override
public WordStat getWordStat(ReceivedText receivedText) {
WordStat wordStat = new WordStat(receivedText);
Map<String, Integer> wordsMap = getWordsMap(filterText(receivedText.getText()));
wordStat.setCountOfWords(getCountOfWords(wordsMap));
wordStat.setFrequencyWords(
filterWordsMap(wordsMap, wordStat.getCountOfWords(), receivedText.getPercent())
);
return wordStat;
}
}
package testText;
import ru.lexmin.lexm_core.TextAnalyzer;
import ru.lexmin.lexm_core.TextAnalyzerImp;
import ru.lexmin.lexm_core.dto.ReceivedText;
import ru.lexmin.lexm_core.dto.WordStat;
public class Main {
public static void main(String[] args) {
final int PERCENT = 80;
TextAnalyzer ta = new TextAnalyzerImp();
String friends = "There's nothing to tell! He's .... тут текст двух серий первого сезона";
ReceivedText receivedText = new ReceivedText(friends, PERCENT);
WordStat wordStat = ta.getWordStat(receivedText);
System.out.println("Количество слов в тексте: " + wordStat.getCountOfWords());
System.out.println("Количество слов, покрывающие 80% текста: " + wordStat.getFrequencyWords().size());
System.out.println("Список слов, покрывающих 80% текста");
wordStat.getFrequencyWords().forEach((word, count) -> System.out.println(word));
}
}
К сожалению, не доступен сервер mySQL