Help us understand the problem. What is going on with this article?

異体字同一視検索を実装メモ

More than 1 year has passed since last update.

環境

C#、Linq to Entity、SQL Serverです。

はじめに

以下を参考にさせていただきました。(感謝)
karak 異体字同一視検索

異体字とは

http://d.hatena.ne.jp/keyword/%B0%DB%C2%CE%BB%FA

標準の字体と同じ意味・発音を持つが、表記に差異がある文字のこと。手書きによる個人差から生じたもの、新字・旧字(簡体・繁体)の違いによるものがある。

目的

峰さん、嶺さん、峯さん、いっぱいいますね。
いざ検索しようとして、みねってどんな字だったっけ?全然ヒットしない!
という事もあろうかと思います。
同様に浜さん、濱さん、濵さん、なかなか検索ヒットできません。

さらにたとえば濵嵜(はまざき)さんという人を検索したい場合、なかなか変換ではでてこないですし、ひらがなも、はまざき・はまさき どっちだったけ?となりがちです。

という時に、「浜」でも「濱」「濵」さんが検索ヒットできるように異体字を同一視して検索できるように実装しました。

異体字辞書の作成

まずは異体字の辞書を用意しました。
DB化するか悩んだのですが、漢字であるしほぼ変わらないであろうことからコードに書いてます。
具体的には以下のような感じです。

var variants = new List<KeyValuePair<string, string>>()
{
    new KeyValuePair<string, string>("濱", "濱|頻|濵|浜|滨"),
    new KeyValuePair<string, string>("浜", "浜|濵|濱"),
    new KeyValuePair<string, string>("領", "領|阾|袊|嶺|岭|领"),
    new KeyValuePair<string, string>("岭", "岭|領|岺|嶺"),
    new KeyValuePair<string, string>("嶺", "嶺|領|岭"),
    ...
}

検索用文字列の変換

浜で検索した場合に正規表現で検索したいので、
浜→[浜|濵|濱]と変換します。

たとえば濵嵜(はまざき)さんという人を検索したい場合は検索ワードとしては以下で正規表現で検索するといい感じになりそうです。
[浜|濵|濱][崎|隑|陭|徛|﨑|㟢|碕|埼|嵜]

浜崎 → [浜|濵|濱][崎|隑|陭|徛|﨑|㟢|碕|埼|嵜] という変換は文字列を1文字ずつ先ほどの辞書を元に変換します。

        public static string get(string word)
        {
            var result = "";

            //異体字一覧(辞書)を取得する
            var vari = Dictionaly.GetDictionaly();

            //文字列を1文字ずつに分割して処理する
            foreach (char c in word)
            {
                //文字が異体字リストにあれば、異体字を取得する。
                //ex. 浜 →  [浜|濵|濱]
                var f = vari.FirstOrDefault(x => x.Key == c.ToString());

                //[]で囲む
                if (f.Key != null)
                {
                    result += "[" + f.Value + "]";
                }
                else
                {
                    result += c;
                }

            }

            //結果を返す
            return result;
        }

検索

Linq to Entityに投げ込みます。

Linq to Entityでは正規表現をそのまま検索できないので、SqlFunctionsを使います。
SqlFunctionsはSystem.Data.Objects.SqlClientにあります。

using System.Data.Objects.SqlClient;

//regStringsが検索ワード([浜|濵|濱][崎|隑|陭|徛|﨑|㟢|碕|埼|嵜])等
var query = from c in db.Entity
    where SqlFunctions.PatIndex("%" + regStrings + "%", c.Modid) == 1
    select c;

参考

異体字データベース

Linq to Entityでの正規表現について(stackoverflow)

他にも検索の幅を増やしたい場合には、LinqKit等を使えばより柔軟になりそうです。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away