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