use utf8;

=encoding utf-8

=head1 NAME

Unicode::LineBreak::JA_JP - UAX #14 Unicode 行分割アルゴリズム

=head1 SYNOPSIS

    use Unicode::LineBreak;
    $lb = Unicode::LineBreak->new();
    $broken = $lb->break($string);

=head1 DESCRIPTION

Unicode::LineBreak は、Unicode 標準の附属書14 [UAX #14] で述べる Unicode 行分割アルゴリズムを実行する。
分割位置を決定する際に、附属書11 [UAX #11] で定義される East_Asian_Width 参考特性も考慮する。

=head2 用語

便宜的に以下の用語を使う。

B<強制分割>〔mandatory break〕は、基本規則で定められており、周囲の文字に関係なく義務的に実行される行分割動作。
B<任意分割>は、基本規則で認められており、ユーザが実行すると決めた場合に行われる行分割動作。
[UAX #14] で定義される任意分割にはB<直接分割>〔direct break〕とB<間接分割>〔indirect break〕とがある。

B<音素文字的な文字>〔alphabetic characters〕は、通常、他の文字が分割の機会を与えないかぎり、文字同士の間で行分割できない文字。
B<表語文字的な文字>〔ideographic characters〕は、通常、その前後で行分割できる文字。
[UAX #14] では音素文字的な文字のほとんどを AL に、表語文字的な文字のほとんどを ID に分類している。
これらの用語は文字学の観点からすれば不正確である。
若干の用字系では、個々の文字からは分割位置が明確にならないため、辞書による発見的方法を用いる。

文字列のB<桁数>は、文字列に含まれる文字の数と等しいとはかぎらない。
個々の文字はB<広い>〔wide〕か、B<狭い>〔narrow〕か、前進を伴わない〔nonspacing〕かのいずれかであり、各々 2 桁、1 桁、0 桁を占める。
若干の文字は、使われる文脈によって広くも狭くもなり得る。
カスタマイズによって、文字はより多様な幅を持ちうる。

=head1 PUBLIC INTERFACE

=head2 行の分割

=over 4

=item new ([KEY => VALUE, ...])

I<コンストラクタ>。
KEY => VALUE の対については L</オプション> を参照。

=item $self->break (STRING)

I<インスタンスメソッド>。
Unicode 文字列 STRING を分割し、それを返す。

=item $self->break_partial (STRING)

I<インスタンスメソッド>。
break() と同じだが、文字列を少しずつ追加して入力する場合。
入力が完了したことを示すには、STRING 引数に C<undef> を与える。

=item $self->config (KEY)

=item $self->config (KEY => VALUE, ...)

I<インスタンスメソッド>。
設定を取得または変更する。
KEY => VALUE の対については L</オプション> を参照。

=back

=head2 情報の取得

=over 4

=item context ([Charset => CHARSET], [Language => LANGUAGE])

I<関数>。
キャラクタセット CHARSET および言語コード LANGUAGE から、それを使う言語/地域の文脈を得る。

=item $self->eawidth (STRING)

I<インスタンスメソッド>。
Unicode 文字列 STRING の最初の文字の East_Asian_Width 特性を得る。
EA_Na、EA_N、EA_W、EA_H、EA_F、EA_Z のいずれかの定数が返る。
EA_Z は前進を伴わない (幅のない) ことを意味する。
特性値 A は適切な値に解決する。

=item $self->lbclass (STRING)

I<インスタンスメソッド>。
Unicode 文字列 STRING の最初の文字の行分割特性 (分類) を得る。
AI、SA、SG、XX の各分類は他の適切な分類に解決する。
ただし、東南アジアの用字系のための単語分節が有効になっているときは、対応している用字系 (現在はタイ文字のみ) の文字の特性を SA のまま解決しない。

=item $self->lbrule (BEFORE, AFTER)

I<インスタンスメソッド>。
分類 BEFORE と分類 AFTER の間での行分割規則を得る。
返値については </定数> を参照。

B<注>:
このメソッドは、BK、CM、CR、LF、NL、SP の各分類に関わる規則については適切な値を返せないかもしれない。
また、AI、SA、SG、XX の各分類に関わる規則については意味のある値を返さない。

=item $self->strsize (LEN, PRE, SPC, STR)

=item $self->strsize (LEN, PRE, SPC, STR, MAX)

I<インスタンスメソッド>。
MAX を指定しないと、[UAX #11] で定義された文字幅に基づいて、Unicode 文字列 PRE.SPC.STR のI<桁数>を算出する。
正の値 MAX を指定すると、PRE.SPC.SUBSTR の桁数が MAX を超えないような STR の最長の部分文字列 SUBSTR のI<文字数>を返す。

=back

=head2 オプション

L</new>、L</config> の両メソッドには以下の対を指定できる。

=over 4

=item CharactersMax => NUMBER

行に含みうる最大の文字数。行末の空白文字と改行の文字列を除く。
文字数は一般に行の長さを表さないことに注意。
初期値は C<998>。

=item ColumnsMin => NUMBER

任意分割された行の、改行の文字列と行末の空白文字を含めない最小桁数。
初期値は C<0>。

=item ColumnsMax => NUMBER

行の、改行の文字列と行末の空白文字を含めない最大桁数。つまり、行の最大長。
初期値は C<76>。

=back

L</UrgentBreaking> オプションおよび L</ユーザ定義の行分割動作> も参照。

=over 4

=item Context => CONTEXT

言語/地域の文脈を指定する。
現在使える文脈は C<"EASTASIAN"> か C<"NONEASTASIAN">。
初期の文脈は C<"NONEASTASIAN">。

=item Format => METHOD

分割した行を整形する方法を指定する。

=over 4

=item C<"DEFAULT">

初期の方法。
任意分割の位置に改行を挿入するだけ。

=item C<"NEWLINE">

L</Newline> オプションで指定したもので改行を置き換える。
改行の前とテキスト終端の空白文字を除去する。
テキスト終端に改行がなければ追加する。

=item C<"TRIM">

任意分割の位置に改行を挿入する。
改行の前の空白文字を除去する。

=item サブルーチンへの参照

L</行の整形> を参照。

=back

=item HangulAsAL => C<"YES"> | C<"NO">

ハングル音節とハングル連結チャモ〔conjoining jamo〕を音素文字的な文字 (AL) と扱う。
初期値は C<"NO">。

=item LegacyCM => C<"YES"> | C<"NO">

前に空白文字がついた結合文字を単独の結合文字 (ID) と扱う。
Unicode 5.0 版からは、空白文字のこのような使いかたは推奨されない。
初期値は C<"YES">。

=item Newline => STRING

改行の文字列とする Unicode 文字列。
初期値は C<"\n">。

=item NSKanaAsID => C<">CLASS...C<">

CLASS で指定した分類に基づき、一部の行頭禁則文字 (NS) を通常の表語文字的な文字 (ID) と扱う。
CLASS には以下の部分文字列を含められる。

=over 4

=item C<"ALL">

下記の文字すべて。
C<"YES"> も同じ。

=item C<"ITERATION MARKS">

表語文字的な繰り返し記号。
U+3005 繰返し記号、U+303B ゆすり点、U+309D 平仮名繰返し記号、U+309E 平仮名繰返し記号 (濁点)、U+30FD 片仮名繰返し記号、U+30FE 片仮名繰返し記号 (濁点)。

注。仮名ではないものもある。

=item C<"KANA SMALL LETTERS">

=item C<"PROLONGED SOUND MARKS">

小書き仮名。

長音記号。
U+30FC 長音記号、U+FF70 長音記号 (代替名称)。

注。これらの文字は行頭禁則文字と扱われることも、通常の表語文字的な文字と扱われることもある。[JIS X 4051] 6.1.1 参照。

=item C<"MASU MARK">

U+303C ます記号。

注。この文字は仮名ではないが、通常 C<"ます"> や C<"マス"> の略記として用いられる。

注。この文字は [UAX #14] では行頭禁則文字 (NS) に分類されるが、[JIS X 4051] では文字クラス (13) (ID に相当) に分類される。

=item C<"NO">

初期値。
以上のいずれの文字も ID と扱わない。

=back

=item SizingMethod => METHOD

文字列の長さを算出する方法を指定する。
以下のオプションが使える。

=over 4

=item C<"DEFAULT">

初期の方法。
strsize() を使う。

=item C<"NARROWAL">

ラテン、ギリシア、キリルの各用字系では、特定の文字が曖昧 (A) の East_Asian_Width 特性を持っている。このため、こういった文字は C<"EASTASIAN"> 文脈で広い文字と扱われる。
このオプションでは、そのような文字を常に狭い文字と扱う。

=item サブルーチンへの参照

L</文字列長の算出> を参照。

=back

=item UrgentBreaking => METHOD

長すぎる行の扱いかたを指定する。
以下のオプションが使える。

=over 4

=item C<"CROAK">

エラーメッセージを出力して死ぬ。

=item C<"FORCE">

長すぎる文字列を無理やり分割する。

=item C<"NONBREAK">

初期の方法。
長すぎる文字列も分割しない。

=item サブルーチンへの参照

L</ユーザ定義の行分割動作> を参照。

=back

=item UserBreaking => C<[>METHOD, ...C<]>

ユーザ定義の行分割動作を指定する。
METHOD には以下のものを指定できる。

=over 4

=item C<"NONBREAKURI">

URI を分割しない。
現在、HTTP(S) と (S)FTP(S) の URI に対応している。

=item C<"BREAKURI">

URI を SOLIDUS (スラッシュ) の前で分割する。
初期設定では、URI を SOLIDUS のI<後>で分割する。

=item C<[> REGEX, SUBREF C<]>

正規表現 REGEX にマッチする文字列を、SUBREF で参照されるサブルーチンで分割する。
詳細は L</ユーザ定義の行分割動作> を参照。

=back

=back

=head2 定数

=over 4

=item C<EA_Na>, C<EA_N>, C<EA_A>, C<EA_W>, C<EA_H>, C<EA_F>, C<EA_Z>

[UAX #11] で定義される 6 つの East_Asian_Width 特性を表す値と、前進を伴わないことを表す EA_Z。

=item C<LB_I<??>>

[UAX #14] で定義される 36 の行分割特性 (分類) を表す値。

=item C<@LB_CLASSES>

上の分類の名前すべての配列。

=item C<MANDATORY>, C<DIRECT>, C<INDIRECT>, C<PROHIBITED>

行分割動作を表す 4 つの値。

強制分割、直接分割も間接分割も認める、間接分割を認めるが直接分割は禁ずる、分割を禁ずる。

=item C<$UNICODE_VERSION>

このモジュールが参照する Unicode 標準の版を示す文字列。

=back

=head1 CUSTOMIZATION

=head2 行の整形

L</Format> オプションにサブルーチンへの参照を指定する場合、そのサブルーチンは 3 つの引数を取らなければならない。

    修正後 = &サブルーチン(SELF, EVENT, STR);

SELF はオブジェクトのインスタンス、EVENT はサブルーチンが呼ばれた文脈を表す文字列、STR は分割位置の前または後の Unicode 文字列の断片。

    EVENT |駆動の契機           |STR
    -----------------------------------------------------------------
    "sot" |テキスト先頭         |最初の行の断片
    "sop" |強制分割の後         |次の行の断片
    "sol" |任意分割の後         |続きの行の断片
    ""    |分割の直前           |行全体 (終端の空白文字を除く)
    "eol" |任意分割             |分割位置の前の空白文字
    "eop" |強制分割             |改行とその前の空白文字
    "eot" |テキスト終端         |テキスト終端の空白文字 (と改行)
    -----------------------------------------------------------------

サブルーチンは、テキストの断片を修正して返さなければならない。なにも修正しなかったことを示すには、C<undef> を返せばよい。
なお、C<"sot">、C<"sop">、C<"sol"> の文脈での修正はその後の分割位置の決定に影響するが、ほかの文脈での修正は影響しない。

たとえば次のコードは、行末の空白を取り除いて行折りをする。

    sub fmt {
        if ($_[2] =~ /^eo/) {
            return "\n";
      	}
        return undef;
    }
    my $lb = Unicode::LineBreak->new(Format => \&fmt);
    print $lb->break($text);

=head2 ユーザ定義の行分割動作

任意分割によって生じる行が CharactersMax、ColumnsMin、ColumnsMax のいずれかの制限を超えると見込まれるときは、引き続く文字列に対してB<緊急分割>を実行できる。
L</UrgentBreaking> オプションにサブルーチンへの参照を指定する場合、そのサブルーチンは 5 つの引数を取らなければならない。

    分割後 = &サブルーチン(SELF, LEN, PRE, SPC, STR);

SELF はオブジェクトのインスタンス、LEN は先立つ行の長さ、PRE はその行の Unicode 文字列、SPC は追加される空白文字、STR は分割すべき Unicode 文字列。

サブルーチンは、文字列 STR を分割した結果の配列を返さなければならない。

たとえば次のコードは、若干の化学物質 (チチンのような) の名称にハイフンを挿入し、行折りできるようにする。

    sub hyphenize {
	return map {$_ =~ s/yl$/yl-/; $_} split /(\w+?yl(?=\w))/, $_[4];
    }
    my $lb = Unicode::LineBreak->new(UrgentBreaking => \&hyphenize);
    print $lb->break("Methionylthreonylthreonylglutaminyl...");

L</UserBreaking> オプションの要素に [REGEX, SUBREF] の配列参照を指定する場合、サブルーチンは 2 つの引数を取らなければならない。

    分割後 = &サブルーチン(SELF, STR);

SELF はオブジェクトのインスタンス、STR は REGEX にマッチする分割すべき Unicode 文字列。

サブルーチンは、文字列 STR を分割した結果の配列を返さなければならない。

=head2 文字列長の算出

L</SizingMethod> オプションにサブルーチンへの参照を指定する場合、そのサブルーチンは 5 つか 6 つの引数を取らなければならない。

    桁数 = &サブルーチン(SELF, LEN, PRE, SPC, STR);

    文字数 = &サブルーチン(SELF, LEN, PRE, SPC, STR, MAX);

SELF はオブジェクトのインスタンス、LEN は先行する文字列の長さ、PRE は先行する Unicode 文字列、SPC は追加される空白文字、STR は処理する Unicode 文字列。

ひとつめの形式では、サブルーチンは C<PRE.SPC.STR> の桁数を算出して返さなければならない。
桁数は整数でなくてもよい。桁数の単位は随意に選べるが、L</ColumnsMin> オプションおよび L</ColumnsMax> オプションのそれと一致させなければならない。

ふたつめの形式では、サブルーチンは STR の部分文字列の I<Unicode 文字の数>の最大値を返さなければならない。部分文字列 SUBSTR は PRE.SPC.SUBSTR の桁数が MAX を超えないように取る。この形式は L</UrgentBreaking> オプションを C<"FORCE"> に設定した場合に使う。後の形式を実装したくなければ、C<undef> を返さなければならない。

初期値では、文字列長の算出には strsize() を使っている。

=head2 文字の分類と行分割の基本規則

文字の分類と行分割の基本的な規則は L<Unicode::LineBreak::Data> と L<Unicode::LineBreak::Rules> で定義している。
これらをカスタマイズしたい場合は、ソースパッケージの F<data> ディレクトリの中を見ること。

=head2 設定ファイル

L</new> メソッドおよび L</config> メソッドのオプション引数の組み込み初期値は、 設定ファイルで上書きできる。
F<Unicode/LineBreak/Defaults.pm>。
詳細は F<Unicode/LineBreak/Defaults.pm.sample> を読んでほしい。

=head1 BUGS

バグやバグのような動作は、開発者に教えてください。L</AUTHOR> を参照。

=head1 VERSION

L<Unicode::LineBreak::Version> を参照してほしい。

このモジュールの開発版が
L<http://hatuka.nezumi.nu/repos/Unicode-LineBreak/>
にある。

=head2 標準への適合性

このモジュールで用いている文字の特性値は、Unicode 標準 5.1.0 版による。

このモジュールでは、実装水準 UAX14-C2 を実装しているつもり。

=over 4

=item *

一部の表語文字的な文字を NS として扱うか ID として扱うかを選べる。

=item *

ハングル音節およびハングル連結チャモを ID として扱うか AL として扱うかを選べる。

=item *

AI に分類される文字を AL と ID のどちらに解決するかを選べる。

=item *

CB に分類される文字は解決しない。

=item *

東南アジア言語の単語分節に対応しない場合は、
SA に分類される文字は AL に解決する。
ただし、General_Category 特性が Mn か Mc である文字は CM に解決する。

=item *

SG や XX に分類される文字は AL に解決する。

=back

=head1 REFERENCES

=over 4

=item [JIS X 4051]

JIS X 4051:2004
I<日本語文書の組版方法>.
日本規格協会, 2004.

=item [UAX #11]

A. Freytag (2008).
I<Unicode Standard Annex #11: East Asian Width>, Revision 17.
L<http://unicode.org/reports/tr11/>.

=item [UAX #14]

A. Freytag and A. Heninger (2008).
I<Unicode Standard Annex #14: Unicode Line Breaking Algorithm>, Revision 22.
L<http://unicode.org/reports/tr14/>.

=back

=head1 SEE ALSO

L<Text::LineFold::JA_JP>, L<Text::Wrap>.

=head1 AUTHOR

Copyright (C) 2009 Hatuka*nezumi - IKEDA Soji <hatuka(at)nezumi.nu>.

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