ending as $ending) { // code... if ($ending[4] < $confidence) { continue; } switch ($type) { case '.n:base.': if ($ending[2] !== '.n.' || strpos($ending[3], $grammar) !== 0) { continue 2; } break; case '.ti:base.': if ($ending[2] !== '.ti.' && $ending[2] !== '.n.') { continue 2; } break; case '.adj:base.': if ($ending[2] !== '.ti.' && $ending[2] !== '.n.') { continue 2; } break; case '.v:base.': if ($ending[2] !== '.v.') { continue 2; } break; default: continue 2; break; } $endingLen = mb_strlen($ending[0], 'UTF-8'); $wordEnd = mb_substr($base, 0 - $endingLen, null, 'UTF-8'); if ($wordEnd === $ending[0]) { // 匹配成功 $word = mb_substr($base, 0, mb_strlen($base, 'UTF-8') - $endingLen, 'UTF-8').$ending[1]; // 尝试sandhi // TODO 加两个sandhi $hasSandhi = false; foreach ($case->union as $sandhi) { $sandhiLen = mb_strlen($sandhi[0], 'UTF-8'); $sandhiEnd = mb_substr($word, 0 - $sandhiLen, null, 'UTF-8'); if ($sandhiEnd === $sandhi[0]) { $sandhiWord = mb_substr($word, 0, mb_strlen($word, 'UTF-8') - $sandhiLen, 'UTF-8').$sandhi[1]; $count = WordIndex::where('word', $sandhiWord)->select(['count', 'bold'])->first(); if ($count) { $hasSandhi = true; $newWord[] = [ 'word' => $sandhiWord, 'ending' => $ending[1], 'type' => '.un.', 'grammar' => '', 'factors' => "{$word}+{$sandhi[2]}", 'count' => $count->count, 'bold' => $count->bold, ]; // 添加一个去掉ti的数据 if ($sandhi[2] === 'iti') { $newWord[] = [ 'word' => mb_substr($sandhiWord, 0, -2, 'UTF-8'), 'ending' => $ending[1], 'grammar' => $ending[3], 'factors' => "{$base}+[{$ending[1]}]", 'count' => $count->count, 'bold' => $count->bold, ]; } } } } $count = WordIndex::where('word', $word)->select(['count', 'bold'])->first(); if ($count || $hasSandhi) { $newWord[] = [ 'word' => $word, 'ending' => $ending[1], 'grammar' => $ending[3], 'factors' => "{$base}+[{$ending[1]}]", 'count' => $count ? $count->count : 0, 'bold' => $count ? $count->bold : 0, ]; } } } return $newWord; } private function endingMatch($base, $ending, $array = null) { $case = new CaseEnding; $output = []; $endingLen = mb_strlen($ending[0], 'UTF-8'); $wordEnd = mb_substr($base, 0 - $endingLen, null, 'UTF-8'); if ($wordEnd === $ending[0]) { // 匹配成功 $word = mb_substr($base, 0, mb_strlen($base, 'UTF-8') - $endingLen, 'UTF-8').$ending[1]; if (is_array($array)) { if (! isset($array[$word])) { $count = WordIndex::where('word', $word)->select(['count', 'bold'])->first(); } } else { $count = WordIndex::where('word', $word)->select(['count', 'bold'])->first(); } if (isset($count) && $count) { $output[$word] = ['count' => $count->count, 'bold' => $count->bold]; } else { $output[$word] = false; } // 尝试sandhi // TODO 加两个sandhi foreach ($case->union as $sandhi) { $sandhiLen = strlen($sandhi[0]); $sandhiEnd = mb_substr($word, 0 - $sandhiLen, null, 'UTF-8'); if ($sandhiEnd === $sandhi[0]) { $sandhiWord = mb_substr($word, 0, mb_strlen($word, 'UTF-8') - $sandhiLen, 'UTF-8').$sandhi[1]; if (is_array($array)) { if (! isset($array[$sandhiWord])) { $count = WordIndex::where('word', $sandhiWord)->select(['count', 'bold'])->first(); } } else { $count = WordIndex::where('word', $sandhiWord)->select(['count', 'bold'])->first(); } if (isset($count) && $count) { $output[$sandhiWord] = ['count' => $count->count, 'bold' => $count->bold]; } else { $output[$sandhiWord] = false; } } } } return $output; } /** * 从词干到单词的变化 * * @return array */ public function BaseToWord($base, $confidence = 0.5) { $newWord = []; $case = new CaseEnding; foreach ($case->ending as $ending) { // code... if ($ending[4] < $confidence) { continue; } /* $matched = $this->endingMatch($base,$ending,$newWord); foreach ($matched as $key => $new) { $newWord[$key] = $new; } */ $endingLen = mb_strlen($ending[0], 'UTF-8'); $wordEnd = mb_substr($base, 0 - $endingLen, null, 'UTF-8'); if ($wordEnd === $ending[0]) { // 匹配成功 $word = mb_substr($base, 0, mb_strlen($base, 'UTF-8') - $endingLen, 'UTF-8').$ending[1]; if (! isset($newWord[$word])) { $count = WordIndex::where('word', $word)->select(['count', 'bold'])->first(); if ($count) { $newWord[$word] = ['count' => $count->count, 'bold' => $count->bold]; } else { $newWord[$word] = false; } } // 尝试sandhi // TODO 加两个sandhi foreach ($case->union as $sandhi) { $sandhiLen = mb_strlen($sandhi[0], 'UTF-8'); $sandhiEnd = mb_substr($word, 0 - $sandhiLen, null, 'UTF-8'); if ($sandhiEnd === $sandhi[0]) { $sandhiWord = mb_substr($word, 0, mb_strlen($word, 'UTF-8') - $sandhiLen, 'UTF-8').$sandhi[1]; if (! isset($newWord[$sandhiWord])) { $count = WordIndex::where('word', $sandhiWord)->select(['count', 'bold'])->first(); if ($count) { $newWord[$sandhiWord] = ['count' => $count->count, 'bold' => $count->bold]; } else { $newWord[$sandhiWord] = false; } } } } } } $result = []; foreach ($newWord as $key => $value) { // code... if ($value !== false) { $result[] = ['word' => $key, 'ending', 'count' => $value['count'], 'bold' => $value['bold']]; } } return $result; } /** * 从单词到词干的变化 * 小蝌蚪找妈妈 * * @param string $word 输入 * @param int $deep 搜索深度 * @param bool $verify 是否验证单词存在 * @return array */ public function WordToBase($word, $deep = 1, $verify = true) { $newWords = []; $newBase = []; $input[$word] = true; $case = new CaseEnding; for ($i = 0; $i < $deep; $i++) { // code... foreach ($input as $currWord => $status) { // code... if ($status) { $input[$currWord] = false; foreach ($case->ending as $ending) { // code... if ($ending[4] < 0.5) { continue; } $endingLen = mb_strlen($ending[1], 'UTF-8'); $wordEnd = mb_substr($currWord, 0 - $endingLen, null, 'UTF-8'); if ($wordEnd === $ending[1]) { // 匹配成功 $base = mb_substr($currWord, 0, mb_strlen($currWord, 'UTF-8') - $endingLen, 'UTF-8').$ending[0]; if (! isset($newBase[$base])) { $newBase[$base] = []; } $info = [ 'word' => $currWord, 'type' => $ending[2], 'grammar' => $ending[3], 'parent' => $base, 'factors' => "{$base}+[{$ending[1]}]", 'confidence' => $ending[4], ]; array_push($newBase[$base], $info); if ($ending[2] === '.n.') { $info['type'] = '.ti.'; array_push($newBase[$base], $info); $info['type'] = '.adj.'; array_push($newBase[$base], $info); } if ($ending[2] === '.ti.') { $info['type'] = '.adj.'; array_push($newBase[$base], $info); } } } } } foreach ($newBase as $currWord => $value) { // 把新词加入列表 if (! isset($input[$currWord])) { $input[$currWord] = true; } } } if ($verify) { $output = []; foreach ($newBase as $base => $rows) { // code... if (($verify = $this->VerifyBase($base, $rows)) !== false) { $output[$base] = $verify; } } if (count($output) == 0) { // 如果验证失败 输出最可能的结果 $short = 10000; $shortBase = ''; foreach ($newBase as $base => $rows) { if (mb_strlen($base, 'UTF-8') < $short) { $short = mb_strlen($base, 'UTF-8'); $shortBase = $base; } } foreach ($newBase as $base => $rows) { if ($base == $shortBase) { $output[$base] = $rows; } } } return $output; } else { return $newBase; } } /** * 验证base在字典中是否存在 */ public function VerifyBase($base, $rows) { // $output = []; $dictWords = UserDict::where('word', $base) ->select(['type', 'grammar']) ->groupBy(['type', 'grammar']) ->get(); if (count($dictWords) > 0) { $newBase[$base] = 1; $case = []; // 字典中这个拼写的单词的语法信息 foreach ($dictWords as $value) { if ($value->type === '.n.') { $arrGrammar = explode('$', $value->grammar); $case[$value->type.$arrGrammar[0]] = 1; } else { $case[$value->type] = 1; } } foreach ($rows as $value) { // 根据输入的猜测的type,grammar拼接合理的 parent 语法信息 switch ($value['type']) { case '.n.': $parentType = '.n:base.'; break; case '.ti.': $parentType = '.ti:base.'; break; case '.v.': $parentType = '.v:base.'; break; default: $parentType = ''; break; } if (! empty($value['grammar']) && $value['type'] === '.n.') { $arrGrammar = explode('$', $value['grammar']); $parentType .= $arrGrammar[0]; } // 只保存语法信息合理的数据 if (isset($case[$parentType])) { array_push($output, $value); } } return $output; } else { return false; } } }