NAME

perlunicode - Perl における Unicode サポート


DESCRIPTION

重要な警告

Uncode サポートは大規模な要求です。 Perl は標準 Unicode や付随する技術的なレポートを一つ残らず 実装しているわけではありませんが、多くの Unicode 機能を サポートしています。

Perl で Unicode を使うことを学びたい人は、多分このリファレンスを読む前に the Perl Unicode tutorial, perlunitut を 読んだ方がよいでしょう。

入出力層

Perl は、ファイルハンドルが ":utf8" 層を指定してオープンされると、 ファイルハンドルが Perl の内部 Unicode エンコーディング (UTF-8, または EBCDIC の時は UTF-EBCDIC) を使うことが分かります。 その他のエンコーディングは、":encoding(...)" 層を使うことで、 入力時の Perl のエンコーディングへの変換や出力時の Perl の エンコーディングからの変換を行えます。 open を参照してください。

Perl のソース自身が UTF-8 であることを示すには、use utf8; を 使ってください。

正規表現

正規表現コンパイラは多態的なオペコードを生成します。 つまり、パターンはデータに対して適用され、データが内部で UTF-8 で エンコードされている場合には Unicode 文字スキームに自動的に 切り替わります -- さもなければ、バイトデータで表されている場合には 伝統的なバイトスキームが使われます。

use utf8 still needed to enable UTF-8/UTF-EBCDIC in scripts

互換性のために、ASCII ベースのマシンにおいて Perl スクリプトそれ自身の 中の UTF-8 を(文字列や正規表現リテラル、あるいは変数名で) 認識可能に するためや、EBCDIC ベースのマシンで UTF-EBCDIC を認識させるために use utf8 プラグマを明示的に含めなければなりません。 これらは明示的に use utf8 が必要な唯一の場合です。 utf8 を参照してください。

BOM-marked scripts and UTF-16 scripts autodetected

Unicode BOM (UTF-16LE, UTF16-BE, またはUTF-8)で Perl スクリプトが 始まっていたり、スクリプトが BOM がついていない UTF-16(BE か LE のいずれか) であった場合、Perl はそのスクリプトを Unicode であるとして正しく読み込みます(BOM がない UTF-8 は、 効率的に ISO 8859-1 などの 8 ビットエンコーディングと区別したり 認識することができません。)

use encoding needed to upgrade non-Latin-1 byte strings

デフォルトでは、Perl の Unicode モデルにおける基本的な非対称があります: バイト文字列から Unicode 文字列への暗黙の昇格はその文字列が ISO 8859-1 (Latin-1) でエンコードされているものと仮定しますが、 Unicode 文字列からのダウングレードは UTF-8 エンコーディングへと行われます。 これは Unicode の最初の 256 文字が Latin-1 と共通であるからです。

詳細は バイトと文字のセマンティクス を参照してください。

バイトと文字のセマンティクス

バージョン 5.6 から、Perl は論理的なワイド文字を内部的な文字列の 表現のために使っています。

将来は、Perl レベルの操作はバイトではなく文字に対して働くことになるでしょう。

しかしながら、一時的な互換性の措置として、Perl は プログラムに対するバイトセマンティクスから文字セマンティクスへの 安全な移行パスを提供することを目指します。 入力データが文字であると Perl が曖昧さなく決定できる操作については、 Perl は文字セマンティクスに切り替えます。 ユーザーからの付加的な情報抜きに決定することができない操作については Perl は互換性の観点からバイトセマンティクスを選択します。

バイトセマンティクスでは、use locale が有効の場合、Perl は 現在のロケールに関連づけられたセマンティクスを使います。 use locale がない場合、Perl 現在のところ US-ASCII (または Unicode の 用語では Basic Latin) バイトセマンティクスを使います; つまり 番号 128 - 255 の範囲の文字は、その番号以外では未定義です。 つまり、大文字小文字はなく、[:alpha:]\w のような、 どの文字クラスにも含まれません。 (しかし \W クラスや Perl の正規表現拡張 [:^alpha:] には属します。)

この動作は Perl の以前のバージョンとの互換性を維持し、プログラムの 入力が Unicode の文字データのソースであるとマークされていない場合にのみ Perl の操作でバイトセマンティクスを許可します。 そのようなデータは、ファイルハンドル、外部プログラムの呼び出し、 システムから提供される情報(%ENV のような)、ソーステキスト中のリテラルや 定数といったものからくるものです。

bytes プラグマは常に、プラットフォームとは無関係に、特定の レキシカルスコープにおいてバイトセマンティクスを強制します。 bytes を参照してください。

utf8 プラグマは主としてパーサが遭遇するリテラル中の UTF-(8|EBCDIC) の 認識を有効にする互換デバイス(compatibility device)です。 このプラグマは Perl のデフォルトがバイトセマンティクスであるときにのみ 必要であることに注意してください。 文字セマンティクスがデフォルトである場合には、 このプラグマは何もしません。 utf8 を参照してください。

明示的に指定されない限り、Perl の演算子は Unicode データに対しては 文字セマンティクスを用い、非 Unicode データに対しては バイトセマンティクスを用います。 文字セマンティクスの使用の決定はトランスペアレントに行われます。 もし入力データが Unicode ソースから来たもの -- たとえば、 文字エンコーディング層がファイルハンドルに附加されているか リテラルの Unicode 文字列定数がプログラムの中にある -- のであれば 文字セマンティクスが適用されます。 そうでなければ、バイトセマンティクスが有効になります。 bytes プラグマは Unicode データに対してバイトセマンティクスを 強制するときに使うと良いでしょう。

バイトセマンティクスの元での文字列の操作で、Unicode 文字データが 連結された文字列であった場合、新たな文字列は文字セマンティックスを 保ちます。 これは驚きを引き起こすかもしれません: 後述する BUGS を 参照してください。

文字セマンティクスの元では、伝統的にバイトに対して働いていた操作の多くが 文字に対して働きます。 Perl における文字は論理的には 0 から 2**31 までの範囲の数値です。 大きな文字は内部的にはより長いシーケンスにエンコードされる可能性が ありますが、この内部の詳細は Perl プログラムからほとんど隠されています。 詳細は perluniintro を参照してください。

文字セマンティクスの効果

文字セマンティクスは以下の効果を持っています:

Unicode 文字特性

名前付けされた Unicode の特性、用字、ブロックの範囲は \p{} "matches property" 構造やその否定形の \P{} "doesn't match property" を 使った文字クラスで使うことができます。

たとえば、\p{Lu} は Unicode の "Lu" (Letter, uppercase) 特性を持つ任意の 文字にマッチし、\p{M} は "M" (mark -- アクセントなど) 特性を持つ任意の 文字にマッチします。 ブラケットは一文字の特性では省略することができるので、\p{M}\PM と等価です。 \p{Mirrored}\p{Tibetan} など多くの特性が定義されています。

公式の Unicode 用字およびブロックの名前はスペースとダッシュを セパレータとして使っていますが、便利のため、ダッシュ、スペース、 アンダーバーを使うことができ、また、大小文字の違いは重要ではありません。 しかしながら、以下のネーミングにしたがって、首尾一貫して使うことを お勧めします: Unicode の用字、特性、ブロックの名前 (ブロック名に 適用される付加的なルールについて以下を参照してください) から 空白とダッシュを取り除き、単語の先頭を大文字にし残りを小文字にします。 したがって、Latin-1 SupplementLatin1Supplement となります。

\p{}\P{} の両方で、キャレット(^) を最初のブレースと 特性名の間に置くことによって意味を反転することができます: \p{^Tamil}\P{Tamil} と等価です。

注意: ここでの特性、用字、ブロックは 2006 年 7 月の Unicode 5.0.0 に 従っています。

General Category

以下に挙げるのは、Unicode の一般カテゴリ特性(General Category properties) で、 長形式が並んでいます。 たとえば、\p{Lu}\p{UppercaseLetter} は同じものとして 扱うことができます。

    Short       Long
    L           Letter
    LC          CasedLetter
    Lu          UppercaseLetter
    Ll          LowercaseLetter
    Lt          TitlecaseLetter
    Lm          ModifierLetter
    Lo          OtherLetter
    M           Mark
    Mn          NonspacingMark
    Mc          SpacingMark
    Me          EnclosingMark
    N           Number
    Nd          DecimalNumber
    Nl          LetterNumber
    No          OtherNumber
    P           Punctuation
    Pc          ConnectorPunctuation
    Pd          DashPunctuation
    Ps          OpenPunctuation
    Pe          ClosePunctuation
    Pi          InitialPunctuation
                (may behave like Ps or Pe depending on usage)
    Pf          FinalPunctuation
                (may behave like Ps or Pe depending on usage)
    Po          OtherPunctuation
    S           Symbol
    Sm          MathSymbol
    Sc          CurrencySymbol
    Sk          ModifierSymbol
    So          OtherSymbol
    Z           Separator
    Zs          SpaceSeparator
    Zl          LineSeparator
    Zp          ParagraphSeparator
    C           Other
    Cc          Control
    Cf          Format
    Cs          Surrogate   (not usable)
    Co          PrivateUse
    Cn          Unassigned

単一文字の特性は同じ文字で始まる二文字の任意のサブ特性に含まれる すべての文字にマッチします。 LCL& は特別なケースで、これは Ll, Lu, Lt の別名です。

Perl はユーザーが Unicode 文字の内部表現について理解する必要が ないようにしているので、サロゲートの面倒なコンセプトについて 実装する必要はありません。 従って、Cs はサポートされていません。

Bidirectional Character Types

用字はその方向性で異なるので--たとえばヘブライ語は右から左に書きます -- Unicode は以下の特性を BidiClass クラスで提供しています:

    Property    Meaning
    L           Left-to-Right
    LRE         Left-to-Right Embedding
    LRO         Left-to-Right Override
    R           Right-to-Left
    AL          Right-to-Left Arabic
    RLE         Right-to-Left Embedding
    RLO         Right-to-Left Override
    PDF         Pop Directional Format
    EN          European Number
    ES          European Number Separator
    ET          European Number Terminator
    AN          Arabic Number
    CS          Common Number Separator
    NSM         Non-Spacing Mark
    BN          Boundary Neutral
    B           Paragraph Separator
    S           Segment Separator
    WS          Whitespace
    ON          Other Neutrals

たとえば、\p{BidiClass:R} は通常右から左に書く文字にマッチします。

Scripts

\p{Latin}\p{Cyrillic} のような、\p{...}\P{...} で 使うことのできる用字名は以下の通り:

    Arabic
    Armenian
    Balinese
    Bengali
    Bopomofo
    Braille
    Buginese
    Buhid
    CanadianAboriginal
    Cherokee
    Coptic
    Cuneiform
    Cypriot
    Cyrillic
    Deseret
    Devanagari
    Ethiopic
    Georgian
    Glagolitic
    Gothic
    Greek
    Gujarati
    Gurmukhi
    Han
    Hangul
    Hanunoo
    Hebrew
    Hiragana
    Inherited
    Kannada
    Katakana
    Kharoshthi
    Khmer
    Lao
    Latin
    Limbu
    LinearB
    Malayalam
    Mongolian
    Myanmar
    NewTaiLue
    Nko
    Ogham
    OldItalic
    OldPersian
    Oriya
    Osmanya
    PhagsPa
    Phoenician
    Runic
    Shavian
    Sinhala
    SylotiNagri
    Syriac
    Tagalog
    Tagbanwa
    TaiLe
    Tamil
    Telugu
    Thaana
    Thai
    Tibetan
    Tifinagh
    Ugaritic
    Yi
Extended property classes

拡張特性クラスは基本特性を補完し、Unicode データベースの PropList で定義されています:

    ASCIIHexDigit
    BidiControl
    Dash
    Deprecated
    Diacritic
    Extender
    HexDigit
    Hyphen
    Ideographic
    IDSBinaryOperator
    IDSTrinaryOperator
    JoinControl
    LogicalOrderException
    NoncharacterCodePoint
    OtherAlphabetic
    OtherDefaultIgnorableCodePoint
    OtherGraphemeExtend
    OtherIDStart
    OtherIDContinue
    OtherLowercase
    OtherMath
    OtherUppercase
    PatternSyntax
    PatternWhiteSpace
    QuotationMark
    Radical
    SoftDotted
    STerm
    TerminalPunctuation
    UnifiedIdeograph
    VariationSelector
    WhiteSpace

その他にも派生した特性があります:

    Alphabetic  =  Lu + Ll + Lt + Lm + Lo + Nl + OtherAlphabetic
    Lowercase   =  Ll + OtherLowercase
    Uppercase   =  Lu + OtherUppercase
    Math        =  Sm + OtherMath
    IDStart     =  Lu + Ll + Lt + Lm + Lo + Nl + OtherIDStart
    IDContinue  =  IDStart + Mn + Mc + Nd + Pc + OtherIDContinue
    DefaultIgnorableCodePoint
                =  OtherDefaultIgnorableCodePoint
                   + Cf + Cc + Cs + Noncharacters + VariationSelector
                   - WhiteSpace - FFF9..FFFB (Annotation Characters)
    Any         =  Any code points (i.e. U+0000 to U+10FFFF)
    Assigned    =  Any non-Cn code points (i.e. synonym for \P{Cn})
    Unassigned  =  Synonym for \p{Cn}
    ASCII       =  ASCII (i.e. U+0000 to U+007F)
    Common      =  Any character (or unassigned code point)
                   not explicitly assigned to a script
Use of "Is" Prefix

(Perl 5.6 との)後方互換性のため、すべての特性はその名前の前に Is を 置くことができます。 したがって、\P{IsLu}\P{Lu} と等価です。

Blocks

用字 に加え、Unicode では文字の ブロック を定義しています。 用字とブロックの違いは、用字のコンセプトが自然言語に 密着したものであるのに対して、ブロックのコンセプトは 256 の Unicode 文字のグループに基づいたより人工的なグループ分けであることです。 たとえば、Latin 用字は多くのブロックからの文字を含んでいますが、 それらのブロックのすべての文字を含んではいません。 例を挙げると、数字は多くの用字を越えて共有されているので、 (Latin 用字は)数字を含みません。 数字と、句読点のような同様のグループは Common と呼ばれる カテゴリにあります。

用字のより詳しい情報は UTR #24 "Script Names" を参照してください:

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

ブロックについてのより詳しい情報は:

   http://www.unicode.org/Public/UNIDATA/Blocks.txt

ブロック名は In 接頭辞とともに与えられます。 たとえば、カタカナブロックは \p{InKatakana} として参照されます。 In 接頭辞は用字や他のプロパティと衝突しなければ省略することも 可能ですが、混乱のないブロックテストのために常に In を使うことを お勧めします。

以下のブロック名がサポートされています:

    InAegeanNumbers
    InAlphabeticPresentationForms
    InAncientGreekMusicalNotation
    InAncientGreekNumbers
    InArabic
    InArabicPresentationFormsA
    InArabicPresentationFormsB
    InArabicSupplement
    InArmenian
    InArrows
    InBalinese
    InBasicLatin
    InBengali
    InBlockElements
    InBopomofo
    InBopomofoExtended
    InBoxDrawing
    InBraillePatterns
    InBuginese
    InBuhid
    InByzantineMusicalSymbols
    InCJKCompatibility
    InCJKCompatibilityForms
    InCJKCompatibilityIdeographs
    InCJKCompatibilityIdeographsSupplement
    InCJKRadicalsSupplement
    InCJKStrokes
    InCJKSymbolsAndPunctuation
    InCJKUnifiedIdeographs
    InCJKUnifiedIdeographsExtensionA
    InCJKUnifiedIdeographsExtensionB
    InCherokee
    InCombiningDiacriticalMarks
    InCombiningDiacriticalMarksSupplement
    InCombiningDiacriticalMarksforSymbols
    InCombiningHalfMarks
    InControlPictures
    InCoptic
    InCountingRodNumerals
    InCuneiform
    InCuneiformNumbersAndPunctuation
    InCurrencySymbols
    InCypriotSyllabary
    InCyrillic
    InCyrillicSupplement
    InDeseret
    InDevanagari
    InDingbats
    InEnclosedAlphanumerics
    InEnclosedCJKLettersAndMonths
    InEthiopic
    InEthiopicExtended
    InEthiopicSupplement
    InGeneralPunctuation
    InGeometricShapes
    InGeorgian
    InGeorgianSupplement
    InGlagolitic
    InGothic
    InGreekExtended
    InGreekAndCoptic
    InGujarati
    InGurmukhi
    InHalfwidthAndFullwidthForms
    InHangulCompatibilityJamo
    InHangulJamo
    InHangulSyllables
    InHanunoo
    InHebrew
    InHighPrivateUseSurrogates
    InHighSurrogates
    InHiragana
    InIPAExtensions
    InIdeographicDescriptionCharacters
    InKanbun
    InKangxiRadicals
    InKannada
    InKatakana
    InKatakanaPhoneticExtensions
    InKharoshthi
    InKhmer
    InKhmerSymbols
    InLao
    InLatin1Supplement
    InLatinExtendedA
    InLatinExtendedAdditional
    InLatinExtendedB
    InLatinExtendedC
    InLatinExtendedD
    InLetterlikeSymbols
    InLimbu
    InLinearBIdeograms
    InLinearBSyllabary
    InLowSurrogates
    InMalayalam
    InMathematicalAlphanumericSymbols
    InMathematicalOperators
    InMiscellaneousMathematicalSymbolsA
    InMiscellaneousMathematicalSymbolsB
    InMiscellaneousSymbols
    InMiscellaneousSymbolsAndArrows
    InMiscellaneousTechnical
    InModifierToneLetters
    InMongolian
    InMusicalSymbols
    InMyanmar
    InNKo
    InNewTaiLue
    InNumberForms
    InOgham
    InOldItalic
    InOldPersian
    InOpticalCharacterRecognition
    InOriya
    InOsmanya
    InPhagspa
    InPhoenician
    InPhoneticExtensions
    InPhoneticExtensionsSupplement
    InPrivateUseArea
    InRunic
    InShavian
    InSinhala
    InSmallFormVariants
    InSpacingModifierLetters
    InSpecials
    InSuperscriptsAndSubscripts
    InSupplementalArrowsA
    InSupplementalArrowsB
    InSupplementalMathematicalOperators
    InSupplementalPunctuation
    InSupplementaryPrivateUseAreaA
    InSupplementaryPrivateUseAreaB
    InSylotiNagri
    InSyriac
    InTagalog
    InTagbanwa
    InTags
    InTaiLe
    InTaiXuanJingSymbols
    InTamil
    InTelugu
    InThaana
    InThai
    InTibetan
    InTifinagh
    InUgaritic
    InUnifiedCanadianAboriginalSyllabics
    InVariationSelectors
    InVariationSelectorsSupplement
    InVerticalForms
    InYiRadicals
    InYiSyllables
    InYijingHexagramSymbols

ユーザ定義文字特性

あなた自身の文字特性を、"In" または "Is" で始まる名前のサブルーチンを 定義することによって持つことができます。 そのサブルーチンは任意のパッケージで定義することができます。 ユーザー定義特性は正規表現の \p 構造や \P 構造で使うことができます。 もしユーザー定義特性をそれがあるパッケージ以外で使いたいのであれば、 パッケージ名を \p (もしくは \P)のために指定する必要があります。

    # assuming property IsForeign defined in Lang::
    package main;  # property package name required
    if ($txt =~ /\p{Lang::IsForeign}+/) { ... }
    package Lang;  # property package name not required
    if ($txt =~ /\p{IsForeign}+/) { ... }

この効果はコンパイル時のもので、一度定義してしまったら 変更できないことに注意してください。

サブルーチンは、ひとつ以上の改行で区切られた特定の形式の文字列を 返さなければなりません。 各行は以下のいずれかの形式でなければなりません:

例えば、両方の日本語の音節(ひらがなとカタカナ)を対象とする特性を 定義するには、以下のように定義します

    sub InKana {
        return <<END;
    3040\t309F
    30A0\t30FF
    END
    }

ヒアドキュメントの終端マーカーは行の先頭に置かれることを思い出してください。 これで、\p{InKana}\P{InKana} を使うことができます。

すでに存在しているブロック特性名を使うこともできます:

    sub InKana {
        return <<'END';
    +utf8::InHiragana
    +utf8::InKatakana
    END
    }

生のブロック範囲ではなく、割り当てられた文字のみにマッチさせたいと 考えているとしましょう: 言い換えれば、文字以外のものを 取り除きたいということです:

    sub InKana {
        return <<'END';
    +utf8::InHiragana
    +utf8::InKatakana
    -utf8::IsCn
    END
    }

否定は否定クラスを定義するのに便利です。

    sub InNotKana {
        return <<'END';
    !utf8::InHiragana
    -utf8::InKatakana
    +utf8::IsCn
    END
    }

共通集合(intersection)は二つ以上のクラスにマッチする共通の文字を得るのに 便利です。

    sub InFooAndBar {
        return <<'END';
    +main::Foo
    &main::Bar
    END
    }

最初の集合に "&" を使わないということを忘れないでください -- そうしてしまうと空との共通集合を取ってしまいます(結果は空集合です)。

ユーザ定義の大文字・小文字の対応関係

同様に、lc()、lcfirst()、uc()、ucfirst() (あるいはその文字列組み込み版)で あなた自身の対応関係を定義することもできます。 原則は ユーザー定義文字特性の場合と似ています: ToLower (lc() と lcfirst()用), ToTitle (ucfirst() の最初の文字用), ToUpper (uc() 用と ucfirst() の 残りの文字用) のような名前のサブルーチンを main パッケージで定義します。

サブルーチンから返される文字列はタブで区切られた 3 つの 16 進数を 必要とします: ソースの範囲の始まり、ソースの範囲の終わり、そして デスティネーション範囲の始まりです。 例を挙げましょう:

    sub ToUpper {
        return <<END;
    0061\t0063\t0041
    END
    }

これは、"a", "b", "c" の文字のみを "A", "B", "C" にマッピングして その他のすべての文字は変更しないという uc() のマッピングを定義しています。

もしソースの範囲に言及することがなければ、つまり、対応関係が単一の 文字から別の単一の文字に変換するものであったならば、ソースの範囲の 終わりは空のままでよいけれども二つのタブは必要です。 例を挙げましょう:

    sub ToLower {
        return <<END;
    0041\t\t0061
    END
    }

"A" を "a" にマッピングしてその他のすべての文字は変更しない lc() の マッピングを定義しています。

(真剣なハッカー専用) デフォルトのマッピングを内省したいのなら、 $Config{privlib}/unicore/To/ というディレクトリにデータを 見つけ出すことができます。 マッピングデータはヒアドキュメントとして返され、utf8::ToSpecFoo$Config{privlib}/unicore/SpecialCasing.txt から派生した特殊な 例外マッピングです。 そのディレクトリで見つけることのできる DigitFold のマッピングは ユーザーがダイレクトにアクセスできず、Unicode::UCD モジュールを使うか 大小文字を無視してマッピングします(Fold マッピングが使われているとき)。

ユーザー定義の大文字・小文字の対応関係に関する最後の注意: これらはスカラが Unicode 文字としてマークされているときにのみ使われます。 古いバイト形式の文字列には影響を及ぼしません。

入出力のための文字エンコーディング

Encode を参照してください。

Unicode 正規表現対応レベル

以下に挙げるリストは、現在対応している全ての機能を記述する、 正規表現のための Unicode 対応のリストです。 "Level N" に対する参照とセクション番号は Unicode Technical Standard #18, "Unicode Regular Expressions", version 11, in May 2005 を参照しています。

Unicode のエンコーディング

Unicode 文字は抽象的な数値である 符号位置 にアサインされています。 これらの数値を使うために、さまざまなエンコーディングが必要となります。

Unicode のセキュリティへの影響

EBCDIC 上の Perl での Unicode

EBCDIC プラットフォームでの Unicode の扱い方は未だ実験的です。 このようなプラットフォームでは、この文書やその他での UTF-8 エンコーディングへの言及は、特に ASCII 対 EBCDIC 問題について 議論されている場合でない限りは、Unicode Technical Report 16 で 定義されている UTF-EBCDIC を意味するものとして読むべきです。 utfebcdic プラグマや ":utfebcdic" 層はありません; 代わりに、"utf8" と ":utf8" が、そのプラットフォームの「自然な」 Unicode の 8 ビットエンコーディングを意味するように再利用されています。 この問題に関する更なる議論については perlebcdic を参照してください。

ロケール

通常ロケールの設定と Unicode は互いに影響を及ぼすことはありませんが、 いくつかの例外があります:

Unicode ではない場合

Perl には入出力を Unicode で行うための多数の方法があり、 @ARGV のように Unicode (UTF-8) として解釈できるようなその他の 「エントリポイント」はほとんどない一方、(何らかのエンコーディングで) Unicode が引数として与えられたり結果として返されるべきにも関わらず、 そうなっていない場所も未だ多くあります。

以下に挙げるのはそのようなインターフェースです。 これらすべてが現在の Perl(5.8.3) では単純に引数と戻り値の両方が バイト文字列か、encoding プラグマが使われていれば UTF-8 文字列で あると仮定しています。

このようなケースにおいて、Perl がなぜ Unicode による解決を しないのかの理由の一つは、答えがオペレーティングシステムや ファイルシステムに強く依存しているからです。 たとえば、ファイル名が Unicode で記述できてエンコーディングが 合っていたとしてもそれは移植性のあるコンセプトではないのです。 同様なことが qx や system にも言えます: 「コマンドラインインターフェース」は Unicode をどのように 扱うのでしょうか?

Unicode を Perl に強制する (あるいは Unicode でないことを Perl に強制する)

ときとして(Unicode ではない場合 を参照)、バイト列を UTF-8 であるように強制したりその逆を行う場合があるかもしれません。 低レベルの呼び出し utf8::upgrade($bytestring) と utf8::downgrade($utf8string[, FAIL_OK]) がその回答です。

utf8::downgrade() は、バイトに収まらない文字を含む文字列の場合は 失敗することがあることに注意してください。

XS で Unicode を使う

Perl の Unicode を XS 拡張で取り扱いたいと思うのなら、以下に挙げる API 群が便利かも知れません。 XS レベルでの Unicode に関しての説明は perlguts/"Unicode Support" を、 API の詳細については perlapi を参照してください。

もっと詳しい情報は、perlapi と、Perl のソースコード配布の utf8.cutf8.h を参照してください。


BUGS

ロケールとの相互作用

Unicode データと共にロケールを使うことはおかしな結果を もたらすことになりやすいです。 現在のところ、Perl は文字に 0..255 の範囲の 8 ビットロケールを 割り当てようとしていますが、このテクニックは Unicode に マップしようとしたときに先の範囲の文字を使用するロケールに対して 明らかに正しくありません。 Perl の Unicode サポートはまた、遅くなりがちです。 Unicode といっしょにロケールを使うことはお勧めできません。

Locale が指定されないときの番号 128 - 255 の範囲の文字の問題

ロケール指定がない場合、その他の文字や符号位置とは異なり、これらの文字は バイトセマンティクスと文字セマンティクスでとても異なったセマンティクスです。 文字セマンティクスでは Unicode 符号位置として解釈され、Latin-1 (ISO-8859-1) として参照されます。 バイトセマンティクスでは、未定義文字として扱われ、保持している セマンティクスはその番号だけで、様々な文字クラスのメンバにはならないことを 意味します。 例えばどれも \w にはマッチングしませんが、全て \W にマッチングします。 これらのクラスのマッチングの他に、これが影響を与えることが知られている 操作は、大文字小文字の変更、大文字小文字を無視した正規表現マッチング、 quotemeta() です。 これにより、符号位置 255 を超える文字が追加されたり削除されたりすると、 文字列のセマンティックスがバイトから文字へ(またはその逆へ)突然 変更されるという予想外の結果を引き起こすことがあります。 この振る舞いは 5.12 で変更される予定ですが、今のところの回避方法は 常に utf8::upgrade($string) を呼び出すか標準モジュール Encodecharnames を使うことです。

エクステンションとの相互作用

Perl がエクステンションとデータをやり取りするとき、そのエクステンションは UTF8 フラグを理解し、また、それに従った振る舞いをすべきです。 エクステンションがこのフラグについて何も知らなければ、そのエクステンションは 正しくないフラグがついたデータを返す可能性があります。

そのため、もし Unicode データを扱おうというのであれば、 Unicode データの 交換に関して何らかの記述があるのなら使うモジュールすべてのドキュメントを 調べてください。 ドキュメントが Unicode に関して何の言及もしていないのなら、最悪のケースを 考慮し、そしてそのモジュールがどのように実装されているかを知るために ソースを見ることになるかもしれません。 完全に Perl で書かれたモジュールは問題を引き起こしません。 他のプログラミング言語で書かれている直接または間接にアクセスするコードに リスクがあるのです。

影響を受けた関数のための、データの劣化(data corruption)を防ぐ単純な 戦略とは、交換するデータのエンコーディングを常に明確にするということです。 エクステンションが取り扱うことができると知っているエンコーディングを 選択してください。 エクステンションに渡す引数を選択したエンコーディングに変換し、 エクステンションから返ってきた結果をそのエンコーディングから 逆方向に変換します。 変換を行ってくれるラッパ関数を書いておいて、 エクステンションが追いついた時に関数を変更できるようにしておきます。

例として、まだ Unicode データを取り扱うようにはできていない、 有名な Foo::Bar::escape_html について述べましょう。 ラッパ関数は引数を生の UTF-8 に変換し、結果を Perl の内部表現に 逆変換します:

    sub my_escape_html ($) {
      my($what) = shift;
      return unless defined $what;
      Encode::decode_utf8(Foo::Bar::escape_html(Encode::encode_utf8($what)));
    }

エクステンションがデータを変換しないけれども格納したり取り出したりするときに、 ときとして危険な Encode::_utf8_on() 関数以外のものを 使うことがあるかもしれません。 C で書かれていて、データを以下のプロトタイプに従って格納したり 取り出したりする param メソッドを持っている 有名な Foo::Bar エクステンションについて述べてみましょう:

    $self->param($name, $value);            # set a scalar
    $value = $self->param($name);           # retrieve a scalar

どのエンコーディングもまだサポートしていないのなら、 以下のような param メソッドを持った派生クラスを 記述することができるでしょう:

    sub param {
      my($self,$name,$value) = @_;
      utf8::upgrade($name);     # make sure it is UTF-8 encoded
      if (defined $value) {
        utf8::upgrade($value);  # make sure it is UTF-8 encoded
        return $self->SUPER::param($name,$value);
      } else {
        my $ret = $self->SUPER::param($name);
        Encode::_utf8_on($ret); # we know, it is UTF-8 encoded
        return $ret;
      }
    }

一部のエクステンションはデータのエントリ/脱出ポイントでフィルターを 提供しています。 たとえば DB_File::filter_store_keyとその仲間です。 あなた使うエクステンションのドキュメントにあるそのようなフィルターに 注意してください。 それらは Unicode データの変化をより容易にします。

速度

一部の関数は UTF-8 でエンコードされた文字列に対して適用したときにバイト エンコードされた文字列に対するときよりも遅くなります。 文字に対して働く必要のある length()、substr()、index()のような関数のすべてと 正規表現マッチングは、データが バイトエンコードされているときには かなり 早く動作できます。

Perl 5.8.0 ではこの遅さはしばしば目立つものでした。 Perl 5.8.1 では少なくとも一部の操作については、遅さを改善することを 期待するキャッシングスキーム(caching scheme)が導入されました。 一般的には、UTF-8 エンコードされた文字列に対する操作はまだ遅いものです。 たとえば、\p{Nd} のような Unicode の特性(文字クラス)は対応する \d のような単純なものよりも目立って遅い(5 倍から10 倍)ことが 知られています(繰り返しますが、d は 10 の ASCII 文字に対して マッチするのに対して Nd は 268 の Unicode 文字にマッチします)。

EBCDIC プラットフォームであり得る問題

以前のバージョンでは、バイトデータと文字データを連結すると、 古い Unicode 文字列が EBCDIC を使っていたとしても、新しい文字列は バイト文字列を ISO 8859-1 (Latin-1) としてデコードして 作成されることがありました。

これらのどれかを発見したら、どうかバグとして報告してください。

perl 5.6.X からコードを移植する

Perl 5.8 は 5.6 とは異なる Unicode モデルを持っています。 5.6 ではプログラマは、ある与えられたスコープが Unicode データを 取り扱うのと Unicode データだけがそのスコープにあることを宣言するのに utf8 プラグマの使用を要求されていました。 5.6 で動いていたプログラムを持っているのなら、以下に挙げる微調整を施す 必要があるでしょう。 例は 5.6 でも動くように書かれているので、安心して試すことができます。


SEE ALSO

perlunitut, perluniintro, Encode, open, utf8, bytes, perlretut, ${^UNICODE} in perlvar