fork download
  1. <?php
  2. //Топ N самых часто встречающихся слов и словосочетаний в тексте(из 2-3-х слов)
  3.  
  4. $stopWords = array('и', 'у', 'к', 'с', 'о', 'от', 'в', 'же', 'из', 'на');
  5. $input = 'Недавно написал свой велосипед и выложил его на хабре. Вот он:
  6. «Простейший Connection pool без DataSource в Java». Статья не из самых удачных,
  7. только прошу больше не минусовать. Итак, чтобы не повторять такие ошибки самому и,
  8. возможно, предостеречь кого-то от таких ошибок, решил перевести статью «Seven Things
  9. You Should Never Code Yourself» достаточно известного в среде open-source деятеля
  10. IT-области — Andy Lester\'а. Итак, кому интересно, прошу под кат.
  11.  
  12. Мы, программисты, любим решать задачи. Мы любим, когда идеи возникают в наших
  13. головах, перенаправляются на наши пальцы и тем самым создаются великолепные решения.
  14.  
  15. Но порой мы слишком быстро вскакиваем и начинаем проворачивать свой код без
  16. учета всех последствий, к которым это может привести. Мы не учитываем, что
  17. кто-то, возможно, уже решил эту проблему, и что уже есть код, доступный для
  18. использования, который был написан, протестирован и продебажен кем-то другим.
  19. Иногда нам просто необходимо остановиться и подумать, прежде чем начать что-то
  20. печатать.
  21.  
  22. Например, если вы столкнетесь с одной из этих семи задач программирования,
  23. то почти всегда вам лучше поискать существующее решение, чем пытаться реализовывать
  24. что-то самостоятельно:
  25.  
  26. 1. Парсинг HTML или XML
  27.  
  28. Задачей, сложностью которой зачастую пренебрегают, по крайней мере на основе того,
  29. сколько раз про него спросили на StackOverflow — является парсинг HTML или XML.
  30. Извлечение данных из произвольного HTML выглядит обманчиво просто, но на самом деле
  31. эта задача должна решаться применением библиотек. Скажем, вы хотите извлечь URL из
  32. тега такого, как
  33.  
  34.  
  35. К тому времени, как вы сделаете еще один цикл в поисках случаев, с которыми
  36. ваш код не может иметь дело, при этом исправляя и тестируя свой код, вы бы могли уже
  37. использовать нужную библиотеку и решили бы все свои проблемы.
  38.  
  39. Я вам привел наглядную историю с примерами: вы потратите намного меньше времени на
  40. поиски существующей библиотеки и на ее изучение, нежели на попытки написать свой
  41. велосипед, который затем придется расширять, чтобы он работал в тех случаях, о
  42. которых вы и не думали, когда начинали его писать.
  43.  
  44. 2. Парсинг CSV и JSON
  45.  
  46. CSV файлы обманчиво просты, но таят в себе некую опасность. Файлы с величинами,
  47. разделенными запятыми тривиальны для парсинга, не так ли?
  48.  
  49. # ID, name, city
  50. 1, Queen Elizabeth II, London
  51.  
  52. Безусловно, пока вам не придется иметь дело с запятыми, заключенными в двойные
  53. кавычки:
  54.  
  55. Вы можете справиться и с этим, пока не придется иметь дело с переводами строк в
  56. середине записи.
  57.  
  58. JSON имеет те же самые опасности, связанные с типами данных, что и CSV, с дополнительной
  59. проблемой, возникающей из-за возможности хранить многоуровневые структуры данных.
  60.  
  61. Уберегите себя от хлопот и неточностей. Любые данные, которые не могут быть обработаны
  62. разделением строки по запятым должны быть обработаны библиотекой.
  63.  
  64. Если читать структурированные данные неструктурированным методом это плохая идея,
  65. то идея изменять данные на месте еще хуже. Люди часто говорят что-то вроде
  66. «Я хочу изменить все теги с такими-то и такими URL так, чтобы у них появивлся
  67. новый атрибут.» Но даже такое, казалось бы, простое дело, как «Я хочу изменить
  68. в каждом пятом поле в этом CSV имя Боб на Стив» таит в себе опасность, потому что,
  69. как было отмечено выше, вы не сможете считывать запятые должным образом. Чтобы все
  70. было правильно, вам необходимо прочитать данные с помощью грамотной библиотеки во
  71. внутреннюю структуру, изменить данные, а затем записать измененные данные обратно
  72. с помощью той же библиотеки. Ничто не представляет такой риск искажения данных,
  73. как если их структура не соответствует вашим ожиданиям.
  74.  
  75. ';
  76.  
  77. //Функция удаляющая слова и словосочетания являющиеся частью больших словосочений
  78. function removeRepetition($moreWords, $words)
  79. {
  80. foreach ($moreWords as $moreWord => $moreCount) {
  81. foreach ($words as $word => $count) {
  82. //если во втором массиве словосочетания, иначе слова
  83. if (preg_match('/\w+ \w+/u', $word)) {
  84. if ((mb_strpos($moreWord, $word) !== false) && ($count == $moreCount)) {
  85. unset($words[$word]);
  86. }
  87. } else {
  88. $severalWords = explode(' ', $moreWord);
  89. $oneWord = array($word);
  90. $matches = array_intersect($oneWord, $severalWords);
  91. if ((count($matches) != 0) && ($moreCount == $count)) {
  92. unset($words[$word]);
  93. }
  94. }
  95. }
  96. }
  97. return $words;
  98. }
  99.  
  100. //Удаляем лишнее - переносы, запятые, стоп слова.
  101. $input = mb_strtolower($input);
  102. $input = preg_replace('/[\\r\\n]/', ' ', $input);
  103. $input = preg_replace('/,/', '', $input);
  104. foreach ($stopWords as $word) {
  105. $input = preg_replace("/\\b$word\\b/u", '', $input);
  106. }
  107.  
  108. $sentences = preg_split('/\./', $input, 0, PREG_SPLIT_NO_EMPTY);
  109.  
  110. //Формируем словосочетания
  111. foreach ($sentences as $sentence) {
  112. $words = preg_split('/ /', $sentence, 0, PREG_SPLIT_NO_EMPTY);
  113. foreach ($words as $key => $word) {
  114. $oneWords[] = $word;
  115. //Прерываем цикл на последнем слове.
  116. if ($key == (count($words) - 1)) {
  117. break;
  118. }
  119. $twoWords[] = $word . ' ' . $words[$key + 1];
  120. if ($key !== 0) {
  121. $threeWords[] = $words[$key - 1] . ' ' . $word . ' ' . $words[$key + 1];
  122. }
  123. }
  124. }
  125.  
  126. //Считаем, удаляем все что было найдено 1 раз и сортируем
  127. $countWords = array_diff(array_count_values($oneWords), array(1));
  128. $countTwoWords = array_diff(array_count_values($twoWords), array(1));
  129. $countThreeWords = array_diff(array_count_values($threeWords), array(1));
  130. arsort($countWords, SORT_NUMERIC);
  131. arsort($countTwoWords, SORT_NUMERIC);
  132. arsort($countThreeWords, SORT_NUMERIC);
  133.  
  134. //Удаляем слова и словосочеания являющиеся часть других
  135. $countWords = removeRepetition($countThreeWords, $countWords);
  136. $countWords = removeRepetition($countTwoWords, $countWords);
  137. $countTwoWords = removeRepetition($countThreeWords, $countTwoWords);
  138.  
  139. $top = array_merge($countWords, $countTwoWords, $countThreeWords);
  140.  
  141. //Выводим результат нашей магии
  142. if ($top == '') {
  143. echo 'Увы, но в данном тексте нет частых слов или словосочетаний встречающихся больше одного раза :(';
  144. } elseif (count($top) == 1) {
  145. foreach ($top as $words => $count) {
  146. echo 'Самое частое слово/словосочетание: "' . $words . '", оно встречается - ' . $count .
  147. ' раз.';
  148. }
  149. } else {
  150. arsort($top);
  151. echo "Самые частые слова/словосочетания:\n";
  152. foreach ($top as $words => $count) {
  153. echo $words . " - встречается " . $count . " раз.\n";
  154. }
  155. }
Success #stdin #stdout 0.02s 20520KB
stdin
Standard input is empty
stdout
Самые частые слова/словосочетания:
не - встречается 13 раз.
вы - встречается 8 раз.
данные - встречается 6 раз.
как - встречается 5 раз.
но - встречается 4 раз.
чтобы - встречается 4 раз.
мы - встречается 4 раз.
данных - встречается 4 раз.
дело - встречается 4 раз.
код - встречается 4 раз.
что - встречается 4 раз.
вам - встречается 4 раз.
свой - встречается 4 раз.
csv - встречается 4 раз.
библиотеки - встречается 3 раз.
изменить - встречается 3 раз.
уже - встречается 3 раз.
все - встречается 3 раз.
иметь дело - встречается 3 раз.
	 - встречается 3 раз.
html - встречается 3 раз.
бы - встречается 3 раз.
парсинг - встречается 3 раз.
что-то - встречается 3 раз.
если - встречается 3 раз.
придется - встречается 3 раз.
необходимо - встречается 2 раз.
чем - встречается 2 раз.
просто - встречается 2 раз.
url - встречается 2 раз.
по - встречается 2 раз.
который - встречается 2 раз.
обманчиво - встречается 2 раз.
то - встречается 2 раз.
времени - встречается 2 раз.
0 - встречается 2 раз.
быть обработаны - встречается 2 раз.
не придется иметь - встречается 2 раз.
html или xml - встречается 2 раз.
парсинг html или - встречается 2 раз.
для - встречается 2 раз.
придется иметь дело - встречается 2 раз.
«я хочу изменить - встречается 2 раз.
вы не - встречается 2 раз.
свой велосипед - встречается 2 раз.
свой код - встречается 2 раз.
еще - встречается 2 раз.
так - встречается 2 раз.
помощью - встречается 2 раз.
себе - встречается 2 раз.
файлы - встречается 2 раз.
опасность - встречается 2 раз.
было - встречается 2 раз.
идея - встречается 2 раз.
этом - встречается 2 раз.
затем - встречается 2 раз.
запятыми - встречается 2 раз.
пока - встречается 2 раз.
json - встречается 2 раз.
решил - встречается 2 раз.
итак - встречается 2 раз.
его - встречается 2 раз.
без - встречается 2 раз.
может - встречается 2 раз.
это - встречается 2 раз.
любим - встречается 2 раз.
— - встречается 2 раз.
когда - встречается 2 раз.
прошу - встречается 2 раз.