Guest User

Untitled

a guest
Apr 26th, 2017
1,537
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.92 KB | None | 0 0
  1. <?php
  2. /*
  3. ***************************************************************************
  4. * Copyright (C) 2008 by Felipe Ribeiro *
  5. * http://www.feliperibeiro.com *
  6. * *
  7. * Permission is hereby granted, free of charge, to any person obtaining *
  8. * a copy of this software and associated documentation files (the *
  9. * "Software"), to deal in the Software without restriction, including *
  10. * without limitation the rights to use, copy, modify, merge, publish, *
  11. * distribute, sublicense, and/or sell copies of the Software, and to *
  12. * permit persons to whom the Software is furnished to do so, subject to *
  13. * the following conditions: *
  14. * *
  15. * The above copyright notice and this permission notice shall be *
  16. * included in all copies or substantial portions of the Software. *
  17. * *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
  19. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
  20. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
  21. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
  22. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
  23. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
  24. * OTHER DEALINGS IN THE SOFTWARE. *
  25. ***************************************************************************
  26. */
  27.  
  28.  
  29. /**
  30. * This class implements the Spell correcting feature, useful for the
  31. * "Did you mean" functionality on the search engine. Using a dicionary of words
  32. * extracted from the product catalog.
  33. *
  34. * Based on the concepts of Peter Norvig: http://norvig.com/spell-correct.html
  35. *
  36. * @author Felipe Ribeiro <[email protected]>
  37. * @date September 18th, 2008
  38. * @package catalog
  39. *
  40. */
  41. class SpellCorrector {
  42. private static $NWORDS;
  43.  
  44. /**
  45. * Reads a text and extracts the list of words
  46. *
  47. * @param string $text
  48. * @return array The list of words
  49. */
  50. private static function words($text) {
  51. $matches = array();
  52. preg_match_all("/[a-z]+/",strtolower($text),$matches);
  53. return $matches[0];
  54. }
  55.  
  56. /**
  57. * Creates a table (dictionary) where the word is the key and the value is it's relevance
  58. * in the text (the number of times it appear)
  59. *
  60. * @param array $features
  61. * @return array
  62. */
  63. private static function train(array $features) {
  64. $model = array();
  65. $count = count($features);
  66. for($i = 0; $i<$count; $i++) {
  67. $f = $features[$i];
  68. $parts = explode("=",$f);
  69. $model[$parts[0]] = intval($parts[1]);
  70. }
  71. return $model;
  72. }
  73.  
  74. /**
  75. * Generates a list of possible "disturbances" on the passed string
  76. *
  77. * @param string $word
  78. * @return array
  79. */
  80. private static function edits1($word) {
  81. $alphabet = 'abcdefghijklmnopqrstuvwxyz';
  82. $alphabet = str_split($alphabet);
  83. $n = strlen($word);
  84. $edits = array();
  85. for($i = 0 ; $i<$n;$i++) {
  86. $edits[] = substr($word,0,$i).substr($word,$i+1); //deleting one char
  87. foreach($alphabet as $c) {
  88. $edits[] = substr($word,0,$i) . $c . substr($word,$i+1); //substituting one char
  89. }
  90. }
  91. for($i = 0; $i < $n-1; $i++) {
  92. $edits[] = substr($word,0,$i).$word[$i+1].$word[$i].substr($word,$i+2); //swapping chars order
  93. }
  94. for($i=0; $i < $n+1; $i++) {
  95. foreach($alphabet as $c) {
  96. $edits[] = substr($word,0,$i).$c.substr($word,$i); //inserting one char
  97. }
  98. }
  99.  
  100. return $edits;
  101. }
  102.  
  103. /**
  104. * Generate possible "disturbances" in a second level that exist on the dictionary
  105. *
  106. * @param string $word
  107. * @return array
  108. */
  109. private static function known_edits2($word) {
  110. $known = array();
  111. foreach(self::edits1($word) as $e1) {
  112. foreach(self::edits1($e1) as $e2) {
  113. if(array_key_exists($e2,self::$NWORDS)) $known[] = $e2;
  114. }
  115. }
  116. return $known;
  117. }
  118.  
  119. /**
  120. * Given a list of words, returns the subset that is present on the dictionary
  121. *
  122. * @param array $words
  123. * @return array
  124. */
  125. private static function known(array $words) {
  126. $known = array();
  127. foreach($words as $w) {
  128. if(array_key_exists($w,self::$NWORDS)) {
  129. $known[] = $w;
  130. }
  131. }
  132. return $known;
  133. }
  134.  
  135.  
  136. /**
  137. * Returns the word that is present on the dictionary that is the most similar (and the most relevant) to the
  138. * word passed as parameter,
  139. *
  140. * @param string $word
  141. * @return string
  142. */
  143. public static function correct($word) {
  144. $word = trim($word);
  145. if(empty($word)) return;
  146.  
  147. $word = strtolower($word);
  148. /* To optimize performance, the serialized dictionary can be saved on a file
  149. instead of parsing every single execution */
  150.  
  151. if(empty(self::$NWORDS)) {
  152.  
  153. if(!file_exists('serialized_dictionary.txt')) {
  154. echo "ERROR!! Please keep serialized_dictionary.txt in the same directory!!";
  155. } else {
  156. $contents = array();
  157. $contents = file("serialized_dictionary.txt");
  158. self::$NWORDS = self::train($contents);
  159. }
  160. }
  161.  
  162. $candidates = array();
  163. if(self::known(array($word))) {
  164. return $word;
  165. } elseif(($tmp_candidates = self::known(self::edits1($word)))) {
  166. foreach($tmp_candidates as $candidate) {
  167. $candidates[] = $candidate;
  168. }
  169. } elseif(($tmp_candidates = self::known_edits2($word))) {
  170. foreach($tmp_candidates as $candidate) {
  171. $candidates[] = $candidate;
  172. }
  173. } else {
  174. return $word;
  175. }
  176.  
  177. $max = 0;
  178. foreach($candidates as $c) {
  179. $value = self::$NWORDS[$c];
  180. if( $value > $max) {
  181. $max = $value;
  182. $word = $c;
  183. }
  184. }
  185. return $word;
  186. }
  187. }
  188.  
  189. ?>
Advertisement
Add Comment
Please, Sign In to add comment