6559


PostgreSQL 9.2.4 + Rails 4.1を使っています。  
DB内のあるカラムに「空間オープンデータを用いたソフトウェア」という文言が入っています。

このとき、以下のようなSQLを発行してもデータが返ってきません（0件）。（実際には画面からフリー入力された文字列をActiveRecordのクエリに渡しています）

[code]

    select * 
    from groups g 
    where 
      g.overview like '%オープンデータ%'
    
[/code]

しかし、「タ」だけ検索すると返ってきます。

[code]

    select * 
    from groups g 
    where 
      g.overview like '%タ%'
    
[/code]

「ソフトウェア」や「空間」でも返ってきます。

[code]

    select * 
    from groups g 
    where 
      g.overview like '%ソフトウェア%'
    
    select * 
    from groups g 
    where 
      g.overview like '%空間%'
    
[/code]

「テ」でも大丈夫です。

[code]

    select * 
    from groups g 
    where 
      g.overview like '%デ%'
    
[/code]

しかし、「デ」や「プ」ではダメです。

[code]

    select * 
    from groups g 
    where 
      g.overview like '%デ%'
    
    select * 
    from groups g 
    where 
      g.overview like '%プ%'
    
[/code]

どうも濁点や半濁点が入るとおかしくなる気がします。  
UnicodeのNFCやNFDが関連してそうな気がしますが、具体的な原因はよくわかりません。

ちなみに `SHOW LC_COLLATE`の結果は`ja_JP.UTF-8`になっています。

原因や解決策（入力された文字を見た目通りに検索する方法）をご存知の方がいたら教えてください。

### EDIT

原因はわかりました。

実際には直接SQLを発行しているのではなく、Railsアプリ内で検索しています。

で、キーボードから直接入力した文字列と、DBから取得した文字列をunpackしてコードポイントを比較してみると、両者が異なっていました。  
(DBに格納されている文字列は濁点や半濁点が1文字として扱われているようです)

[code]

    # キーボードから直接入力する
    irb(main):017:0> o = '空間オープンデータを用いたソフトウェア'
    => "空間オープンデータを用いたソフトウェア"
    
    irb(main):018:0> o.unpack("U*")
    => [31354, 38291, 12458, 12540, 12503, 12531, 12487, 12540, 12479, 12434, 29992, 12356, 12383, 12477, 12501, 12488, 12454, 12455, 12450]
    
    # DBから取得する（gはid指定で取得したActiveRecordのオブジェクト）
    irb(main):019:0> g.overview
    => "空間オープンデータを用いたソフトウェア"
    irb(main):020:0> g.overview.unpack("U*")
    => [31354, 38291, 12458, 12540, 12501, 12442, 12531, 12486, 12441, 12540, 12479, 12434, 29992, 12356, 12383, 12477, 12501, 12488, 12454, 12455, 12450]
    
    # 両者は同一ではない
    irb(main):021:0> o == g.overview
    => false
    
    # キーボードから直接入力した文字列はヒットしない
    irb(main):024:0> Group.where(overview: o).count
       (0.7ms)  SELECT COUNT(*) FROM "groups"  WHERE "groups"."deleted_at" IS NULL AND "groups"."overview" = '空間オープンデータを用いたソフトウェア'
    => 0
    
    # DBから取得した文字列はヒットする
    irb(main):025:0> Group.where(overview: g.overview).count
       (0.6ms)  SELECT COUNT(*) FROM "groups"  WHERE "groups"."deleted_at" IS NULL AND "groups"."overview" = '空間オープンデータを用いたソフトウェア'
    => 1
    
[/code]

見た目には全く同じに見えますが、内部的なコードポイントが異なるため、ヒットする文字列とヒットしない文字列が分かれてしまうようです。（DBはNFDで、画面からの入力した値はNFCになっている）

さて、原因はわかりましたが、最終的なゴールは内部的なコードポイントに左右されず、人間の目に見えるとおりに検索をヒットさせることです。  
なんらかの方法で画面からの入力値とDB内の値やクエリのパラメータを一致させる必要があります。

どうすればズレを無くして一致させることができるでしょうか？  
画面からはNFCで入力されるので、DB側もNFCで統一するのがベストかなと思います。

  * 既存のデータをNFCにコンバートする
  * 新しく登録されるデータもNFCにする

といったアプローチが必要になりそうですが、実際にこうした対応をやっている人がいたら対応方法を教えていただきたいです。  
よろしくお願いします。

## EDIT2

原因は（何らかの特殊な事情で？）NFDの文字列が入力されてしまったことにあるようです。

問題のあるデータからのコピペではなく、キーボードからの打ち直しをしてみると、ちゃんと検索できました。

なので、DBやRailsの問題というよりも、入力した人間に原因がある可能性が高いです。

というわけで、ここではこれ以上の深掘りはできないので、いったん解決済みとしたいと思います。


CC BY-SA 3.0
2015-02-16T06:14:16.633
6551
2015-02-16T10:03:26.027
2015-02-16T10:03:26.027
85
85
question
ruby-on-rails sql rails-activerecord postgresql unicode
「オープンデータ」のような半濁点を含むカタカナがうまく検索できない


質問にあるテキストをコピーして、ファイルに保存し `od -x foo.txt` してみてください。  
半濁音部分が合成文字になっていると思います。おそらく Mac OS X で作成されたテキストかと思います。  
合成文字の無い utf-8 で保存すると正しく検索できると思います。


CC BY-SA 3.0
2015-02-16T07:43:00.000
6559
2015-02-16T07:43:00.000
440
6551
answer


質問にある文字列をWindows上のテキストエディタで見ると一目瞭然ですね。mattnさんの回答が正しそうです。  
![秀丸での見え方](https://i.stack.imgur.com/824ev.png)

"プ"と"デ"が2文字合成ですね。  
Sublime Textだとこんな感じになりました。  
![Sublime Textでの見え方](https://i.stack.imgur.com/61byG.png)


CC BY-SA 3.0
2015-02-16T09:50:46.903
6570
2015-02-16T09:50:46.903
3709
6551
answer