
=pod

=encoding Shift_JIS

=head1 名称

ShiftJIS::Collate - Shift-JIS 文字列の照合

=head1 概要

  use ShiftJIS::Collate;

  @sorted = ShiftJIS::Collate->new(%tailoring)->sort(@source);

=head1 詳細

このモジュールは、B<JIS X 4061:1996> （日本語文字列照合順番）
に基づいて、Shift-JIS 文字列を照合、整列するための関数を提供します。

このモジュールは JIS X 4061:1996 の実装の一つであり、
照合規則は、上記規格に基づいています。
処理系定義項目も参照のこと。

=head2 コンストラクタとテーラリング

C<new> メソッドは、コレータ・オブジェクトを返却します。

   $Collator = ShiftJIS::Collate->new(
      ignoreChar => $regexIgnoredChar,
      kanji => $kanji_class,
      katakana_before_hiragana => $bool,
      level => $collationLevel,
      position_in_bytes => $bool,
      tounicode  => \&sjis_to_unicode,
      preprocess => \&preprocess,
      upper_before_lower => $bool,
   );
   # もし %tailoring が偽（空リスト）なら、
   # $Collator はデフォルトの照合をします。

=over 4

=item ignoreChar

与えられた正規表現にマッチする文字を、照合に際して無視します。

例えば、もし長音記号とその半角形を無視したいなら、以下のようにします。

   ignoreChar => '^(?:\x81\x5B|\xB0)',

=item katakana_before_hiragana

デフォルトでは、平仮名は対応する片仮名よりも前の順序になります。

このパラメータが真なら、この順序を逆にして、片仮名を平仮名の前に置きます。

=item kanji

使用する漢字文字クラスを指定します。漢字文字クラスについて、詳細は後述。

  Class 1: 最小漢字文字クラス
  Class 2: 基本漢字文字クラス
  Class 3: 拡張漢字文字クラス

漢字文字クラスは C<1>, C<2>, C<3> のいずれかの整数値で指定します。
省略された場合、C<2> が用いられます。

この文字クラスでは、拡張漢字文字クラスはサポートされません。
なぜなら、Shift-JIS のレパートリには、すべての CJK 統合漢字が
定義されないからです。

しかし、漢字文字クラスとして C<3> を指定した場合には、
第１および第２水準の漢字を JIS X 0221 順に並べることも可能になります。
この場合、L<tounicode> コードリファレンスとして、
Shift-JIS 漢字を UCS の符号位置に対応付けるサブルーチンを与える
必要があります。

=item level

適用される最大の照合レベルを指定します。照合レベルについて、詳細は後述。

  Level 1: 基本照合規則による照合
  Level 2: 第１照合属性まで考慮した照合（仮名の清濁）
  Level 3: 第２照合属性まで考慮した照合（文字の大小）
  Level 4: 第３照合属性まで考慮した照合（平仮名と片仮名）
  Level 5: 第４照合属性まで考慮した照合（全角と半角）

照合レベルは、C<1> から C<5> までのいずれかの整数値で指定します。
省略時には、level 4 とします。

＜注＞ 照合レベルが C<0> から C<4> でなくて、１ずつ大きいのは、
JIS X 4061 から見ると、直感的ではありません。
UTS #10, ISO/IEC DIS 14651 を参考にしています。
また、JIS X 4061 には、第４照合属性の規定はありません。
第４照合属性は、このモジュールによる追加事項です。

=item tounicode

漢字を UCS 順に並べるとき、C<kanji> を C<3> にした上で、
C<tounicode> パラメータの値として、Shift-JIS の漢字から
UCS の符号位置を返すサブルーチンのリファレンスを指定してください。

このようなサブルーチンは、Shift-JIS で符号化された
第１・第２水準の漢字（文字列）を UCS の符号位置
（C<0x4E00>〜C<0x9FFF> の範囲の整数）に変換するものでなければなりません。

=item position_in_bytes

デフォルトでは、C<index> メソッドは、結果を文字単位で返します。

このパラメータを真にすると、結果をバイト単位で返すようになります。

=item preprocess

これにコードリファレンスを与えると、ソートキーを作成する前に、
照合対象文字列を、与えられたコードリファレンスを用いて変換します。
つまり、コードリファレンスの返り値からソートキーを作成します。

=item upper_before_lower

デフォルトでは、小文字は大文字よりも前の順序になります。

このパラメータが真の場合、この順序が逆になります。

=back

=head2 比較

=over 4

=item C<$result = $Collator-E<gt>cmp($a, $b)>

返り値は以下のようになります。

C<$a> は C<$b> より大きいときは C<1>、
C<$a> は C<$b> に順序が等しいときは C<0>、
C<$a> は C<$b> より小さいときは C<-1>。

=item C<$result = $Collator-E<gt>eq($a, $b)>

=item C<$result = $Collator-E<gt>ne($a, $b)>

=item C<$result = $Collator-E<gt>gt($a, $b)>

=item C<$result = $Collator-E<gt>ge($a, $b)>

=item C<$result = $Collator-E<gt>lt($a, $b)>

=item C<$result = $Collator-E<gt>le($a, $b)>

これらは、照合規則を適用して比較することを除き、
同名の演算子と同様な機能を持ちます。

=back

=head2 ソート

=over 4

=item C<$sortKey = $Collator-E<gt>getSortKey($string)>

ソートキーを返します。

ソートキーをバイナリ比較することで、
文字列の比較結果を得ることができます。

   $Collator->getSortKey($a) cmp $Collator->getSortKey($b)

      は、以下と等価です。

   $Collator->cmp($a, $b)

=item C<@sorted = $Collator-E<gt>sort(@source)>

「単純照合」によって文字列をソートします。

=item C<@sorted = $Collator-E<gt>sortYomi(@source)>

(読み列, 表記列) からなる配列リファレンスを
「読み・表記照合」によってソートします。

例えば、C<@source> の要素は、C<['日本語', 'にほんご']> です。
その反対の C<['にほんご', '日本語']> も使えますが、
(読み列, 表記列) という順序は変わりません。

「読み・表記照合」は２段階で比較をします。

例えば、以下のリストを「読み・表記照合」でソートするとしましょう。

C<['永田', 'ながた']>, C<['小山', 'おやま']>, C<['長田', 'おさだ']>,
C<['長田', 'ながた']>, C<['小山', 'こやま']>.

まず、読み列で順序付けします。
(C<'おさだ'> E<lt> C<'おやま'> E<lt> C<'こやま'> E<lt> C<'ながた'>);

次に、読み列が同じ文字列同士で、表記列を順序付けします。
(読みが C<'ながた'> のものでは、C<'永田'> E<lt> C<'長田'> です)

従って、結果は、以下のようになります： C<['長田', 'おさだ']> E<lt>
C<['小山', 'おやま']> E<lt> C<['小山', 'こやま']> E<lt>
C<['永田', 'ながた']> E<lt> C<['長田', 'ながた']>.

F<sample/yomi.txt> も参照のこと。

=item C<@sorted = $Collator-E<gt>sortDaihyo(@source)>

(読み列, 表記列) からなる配列リファレンスを
「簡易代表読み照合」によってソートします。

注：このモジュールでは「基本代表読み照合」は実装されていません。

「簡易代表読み照合」は５段階で比較をします。

ここに、簡易代表読み照合でソートされたリストの例を示します。

  ['４面体', 'しめんたい'],
  ['２色性', 'にしょくせい'],
  ['４次元', 'よじげん'],
  ['６面体', 'ろくめんたい'],
  ['α崩壊', 'アルファほうかい'],
  ['Γ関数', 'ガンマかんすう'],
  ['β線',   'ベータせん'],
  ['Ｑ値',   'キューち'],
  ['ＪＩＳ', 'じす'],
  ['Perl',   'パール'],
  ['河西',   'かさい'],
  ['河合',   'かわい'],
  ['河田',   'かわだ'],
  ['河内',   'かわち'],
  ['河辺',   'かわべ'],
  ['角田',   'かくた'],
  ['角田',   'かどた'],
  ['関東',   'かんとう'],
  ['河内',   'こうち'],
  ['沢島',   'さわしま'],
  ['沢嶋',   'さわしま'],
  ['沢田',   'さわだ'],
  ['澤島',   'さわしま'],
  ['澤嶋',   'さわしま'],
  ['澤田',   'さわだ'],
  ['角田',   'つのだ'],
  ['土井',   'つちい'],
  ['土居',   'つちい'],
  ['土井',   'どい'],
  ['土居',   'どい'],

(1) 表記列の先頭の文字の文字クラスを比較する。

  数字 ('４面体') < 欧字記号 ('α崩壊') < ラテン ('ＪＩＳ') < 漢字 ('関東').

(2) 読み列の先頭字を比較する。

  e.g. 'しめんたい' < 'にしょくせい' < 'よじげん' < 'ろくめんたい'.

(3) 表記列の先頭字を比較する。

  e.g. ('河西','河田',etc.) < ('角田','角田') < ('関東');

       ('沢島','沢嶋','沢田') < ('澤島','澤嶋','澤田').

(4) 読み列全体を比較する。

  e.g. ['河西', 'かさい'] < ['河合', 'かわい'] < ['河田', 'かわだ'];

       ['角田', 'かくた'] < ['角田', 'かどた'].

(5) 表記列全体を比較する。

  e.g. ['沢島', 'さわしま'] < ['沢嶋', 'さわしま'].

F<sample/daihyo.txt> も参照。

=back

=head2 部分文字列の検索

=over 4

=item C<$position = $Collator-E<gt>index($string, $substring)>

=item C<($position, $length) = $Collator-E<gt>index($string, $substring)>

C<$substring> が C<$string> の一部にマッチする場合、
スカラーコンテキストでは、マッチする部分の最初の出現位置を返します。
リストコンテキストでは、位置とマッチした部分の文字列長さからなる
（２要素の）リストを返します。

B<注意> マッチした部分の長さは、C<$substring> の長さと異なる可能性があります。

C<$substring> が C<$string> のどこにもマッチしない場合、
スカラーコンテキストでは C<-1> を、リストコンテキストでは空リストを返します。

例

  use ShiftJIS::Collate;
  use ShiftJIS::String qw(substr);

  my $Col = ShiftJIS::Collate->new( level => $level );
  my $str = "* ひらがなとカタカナはレベル３では等しいかな。";
  my $sub = "かな";
  my $match;
  if (my @tmp = $Col->index($str, $sub)) {
    $match = substr($str, $tmp[0], $tmp[1]);
  }

If C<$level> is 1, you get C<"がな">;
if C<$level> is 2 or 3, you get C<"カナ">;
if C<$level> is 4 or 5, you get C<"かな">.

もし C<substr> 関数が、Shift-JIS の文字単位で部分文字列を作れないなら、
C<position_in_bytes> を真にしてください。

=back

=head1 NOTE

=head2 照合レベル

照合レベルは、照合順序が決定するまで、順に考慮されます。

デフォルトでは、レベル 1 から 4 までが評価され、レベル 5 は無視されます
(JIS X 4061 ではレベル 5 は規定されていません）。

=over 4

=item Level 1: 基底文字による順序

文字クラスの順序は、以下の通り。

    1   スペース
    2   記述記号
    3   括弧記号
    4   学術記号
    5   一般記号
    6   単位記号
    7   アラビア数字
    8   欧字記号
    9   ラテンアルファベット
   10   仮名（平仮名と片仮名）
   11   漢字
   12   げた記号

アルファベットはアルファベット順に、仮名は五十音順に、漢字は JIS X 0208 の
区点順になる。

げた記号 ('〓', 0x81AC, U+3013) はいかなる文字よりも大きい（順序が最後）。

順序が定義されていない文字、例えば制御文字、罫線記号、未定義文字などは、
照合に際して、完全に無視される（ないのと同じ）。

=item Level 2: 清濁による順序

仮名では、清音文字、濁音文字、半濁音文字の順とする。
例えば、'か' < 'が'; 'は' < 'ば' < 'ぱ' の順。

=item Level 3: 文字の大小による順序。

ラテン文字では、小文字は、大文字よりも前の順序とする。

仮名では、長音記号、小文字、繰返し記号、大文字の順とする。
例えば、'あー' < 'あぁ' < 'あゝ' < 'ああ' の順。

=item Level 4: 用字系による順序

平仮名は、片仮名よりも前の順序とする。例えば 'あ' < 'ア' の順。

=item Level 5: 文字幅による順序

C<Halfwidth and Fullwidth Forms> に属する文字は、
対応する通常の文字よりも後の順序とする。

なお、JIS X 4061 にはレベル 5 に相当する規定はありません。
Level 5 は、このモジュールによる拡張です。

=back

=head2 漢字文字クラス

JIS X 4061 では、３つの漢字文字クラスが規定されています。
このモジュールは、そのうち、最小漢字文字クラスと基本漢字文字クラスを
サポートしています。

=over 4

=item 最小漢字文字クラス

以下の５文字から構成されます：

    '〃' (0x8156, U+3003)
    '仝' (0x8157, U+4EDD)
    '々' (0x8158, U+3005)
    '〆' (0x8159, U+3006)
    '〇' (0x815A, U+3007)

'仝' 以外の漢字は、照合の際に無視されます。

=item 基本漢字文字クラス

最小漢字文字クラスに、第１水準および第２水準の漢字を加えたものです。
第１水準および第２水準の漢字の順序は、JIS の区点位置の順になります。
JIS X 0208 に規定されない漢字は、照合の際に無視されます。

=item 拡張漢字文字クラス

最小漢字文字クラスに、すべての CJK 統合漢字を加えたものです。
CJK 統合漢字の順序は、UCS の符号順になります。

=back

=head2 長音記号と繰返し記号の置き換え

   文字     SJIS    UCS     文字名

   'ー'    0x815B  U+30FC  KATAKANA-HIRAGANA PROLONGED SOUND MARK
   'ｰ'     0xB0    U+FF70  HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
   'ゝ'    0x8154  U+309D  HIRAGANA ITERATION MARK
   'ゞ'    0x8155  U+309E  HIRAGANA VOICED ITERATION MARK
   'ヽ'    0x8152  U+30FD  KATAKANA ITERATION MARK
   'ヾ'    0x8153  U+30FE  KATAKANA VOICED ITERATION MARK

=over 4

=item KATAKANA-HIRAGANA PROLONGED SOUND MARKs

長音記号（半角形を含む）は、前に仮名があれば、
対応する母音字または鼻音字（「あいうえおん」）に置き換えられます。

   例

  'カー'   → 'カア'
  'びー'   → 'びイ'
  'きゃー' → 'きゃア'
  'ピュー' → 'ピュウ'
  'ンー'   → 'ンン'
  'んー'   → 'んン'

=item HIRAGANA- and KATAKANA ITERATION MARKs

繰返し記号（清音）は、前に仮名があれば、
対応する仮名（清音）に置き換えられます。

   例

  'かゝ'   → 'かか'
  'ドゝ'   → 'ドと'
  'んゝ'   → 'んん'
  'カヽ'   → 'カカ'
  'ばヽ'   → 'ばハ'
  'プヽ'   → 'プフ'
  'ヴィヽ' → 'ヴィイ'
  'ピュゝ' → 'ピュゆ'

=item HIRAGANA- and KATAKANA VOICED ITERATION MARKs

繰返し記号（濁音）は、前に仮名があれば、
対応する仮名（濁音）に置き換えられます。

   例

  'はゞ' → 'はば'
  'プゞ' → 'プぶ'
  'プヾ' → 'プブ'
  'こヾ' → 'こゴ'
  'ウヾ' → 'ウヴ'

=item 置き換えのない場合

以上の場合を除き、置き換えは起こりません。

置き換えのない場合、長音記号および繰返し記号は、
他の仮名より後の順になります。

置き換えのない場合としては、例えば、
長音記号の前に CJK 統合漢字がある場合、
繰返し記号の前に数字がある場合、
'アヾ'（'ア' には濁音はありません）があります。

=item 照合順序の例

例えば照合対象文字列「パール」は、３つの照合要素を持ちます。すなわち、
「片仮名のパ」、「片仮名アで置き換えられた長音記号」、「片仮名ル」です。

    例

   「パール」は基底文字列「パアル」に置き換えられます。

     レベル 1 では「はある」に等しい。
     レベル 2 では「ぱある」に等しく、「はある」よりも大きい。
     レベル 3 では「ぱーる」に等しく、「パアル」よりも小さい。
     レベル 4 では「ぱーる」よりも大きい。

=back

=head2 処理系定義項目 [JIS X 4061, 6.2]

  (1) 文字の符号化方法： Shift-JIS.

  (2) 照合対象文字列の最大有効文字数：制限無し

  (3) 文字クラスの追加：なし

  (4) 文字の追加は以下の通りです。

      IDEOGRAPHIC SPACE を「スペース」文字クラスに追加。

      ACUTE ACCENT, GRAVE ACCENT, DIAERESIS, CIRCUMFLEX ACCENT
      を「記述記号」文字クラスに追加。

      APOSTROPHE, QUOTATION MARK を「括弧記号」文字クラスに追加。

      HYPHEN-MINUS を「学術記号」文字クラスに追加。

  (5) ラテンアルファベットにおけるマクロン付き及びサーカムフレックス付き文字
      は、サポートしません。

  (6) 選択した漢字文字クラス：最小漢字文字クラスおよび基本漢字文字クラス

=head1 作者

SADAHIRO Tomoyuki <SADAHIRO@cpan.org> 貞廣 知行

  Copyright(C) 2001-2007, SADAHIRO Tomoyuki. Japan. All rights reserved.

  This module is free software; you can redistribute it
  and/or modify it under the same terms as Perl itself.

=head1 参考

=over 4

=item JIS X 4061:1996

日本語文字列照合順番

=item JIS X 0201:1997

７ビット及び８ビットの情報交換用符号化文字集合

=item JIS X 0208:1997

７ビット及び８ビットの２バイト情報交換用符号化漢字集合

=item JIS X 0221:1995

国際符号化文字集合 (UCS) ― 第１部　体系及び基本多言語面

=item 日本工業標準調査会 (JISC)

L<http://www.jisc.go.jp/>

=item 日本規格協会 (JSA)

L<http://www.jsa.or.jp/>

=item Unicode Collation Algorithm (UTS #10)

http://www.unicode.org/reports/tr10/

=item ISO/IEC DIS 14651

http://wwwold.dkuug.dk/jtc1/sc22/wg20/docs/projects#14651

=item L<ShiftJIS::String>

=item L<ShiftJIS::Regexp>

=back

=cut
