C ++ Strutextライブラリ

はじめに





このテキストは、Strutextライブラリの概要と見なすことができます。これは、著者がC ++での言語テキスト処理のための効果的なアルゴリズムのセットとして考案したものです。 ライブラリコードはGithubのリポジトリにあります。 このライブラリはオープンソースであり、Apache License 2.0、つまり 重要な制限なしに完全に無料で使用できます。







リポジトリへの最後のコミットは2014年2月16日に行われました。つまり、ライブラリは6か月以上開発されていません。 しかし、それにもかかわらず、自然言語でのテキストの処理に関与している開発者にとって有用なライブラリが既に十分に興味深い実装アルゴリズムを持っているように思われます。



cmakeに基づいて実装されたStrutextをビルドします。 ライブラリコードのほとんどはC ++ 2003で実装されていますが、Pythonバージョン2.7で書かれた小さなスクリプトがあります。 このライブラリは、ブーストバージョン1.53以降、およびロギングツールとしてLog4Cplusライブラリを使用します。 現時点では、ライブラリはgccコンパイラを使用してLinuxで構築されていますが、Windowsで構築するのは非常に簡単だと著者は考えています。



正当な問題がおそらく発生します。たとえば、 ICUがある場合、なぜそのようなライブラリが必要なのでしょうか。 著者の観点からすると、ライブラリの一部のコンポーネントは十分に効率的に実装されていません。 実装スタイルは、低レベルCまたは高レベルJavaに基づいています。 著者の観点からすると、この状況では、C ++でICUライブラリを便利かつ効率的に使用することはできません。 また、ICUは形態などの重要なコンポーネントを実装していません。 また、Strutextライブラリの主な利点の1つは、実装された有限状態マシンライブラリに基づいた効果的なテキスト検索アルゴリズムを利用できることです。 一般に、ICUはUNICODEでの文字処理という1つのコンポーネントのみを実装し、この意味で、Strutextライブラリはより多くの機能を提供します。



ライブラリー構造





Strutextは、自然言語のテキストをさまざまなレベルの表現で処理するためのツールとして考えられています。 通常、次のレベルの言語表現が区別されます。



また、他のレベルの言語表現、たとえば実用的表現もありますが、ここでは説明しません。



Strutextライブラリは現在、言語表現の記号レベルと字句レベルを実装しています。 ライブラリの主なコンポーネント:





各コンポーネントの説明には多くのスペースが必要です。 したがって、このテキストでは、シンボルコンポーネントのみを以下で説明します。 聴衆が図書館に興味を示した場合、著者は喜んで他の記事の説明を続けます。 コンポーネントの説明は、対応するプログラミングの分野への入門とも考えられます。 マニュアル、ワードプロセッシングのこのコンポーネントをプログラムで実装する方法。 この意味で、著者は、ライブラリインターフェイスの簡単な説明だけにとどまらず、その根底にあるアイデアと実装方法も示しました。



シンボル処理ライブラリ





UNICODEについて少し





ご存知のように、 UNICODEコンソーシアムは、コンピューターメモリで世界の言語の記号を表すための標準を開発するために作成されました。 コンソーシアムは設立以来、このようなプレゼンテーションの7つのバージョンをすでにリリースしています。 マシンのメモリでは、使用目的に応じて、さまざまな方法で文字をエンコードできます。 たとえば、ファイル内の文字を表すために、サイズを節約することが重要な場合、UTF-8表現が使用されます。 特定の言語機能を使用する必要がない場合は、UTF-16の2バイト表現を使用できます。 UNICODE仕様の全範囲を完全に表示するには、4バイトのUTF-32表現を使用することをお勧めします。



UNICODE標準の文字(文字)はクラスに分類されます。 クラスは比較的少ないので、それらのいくつかをリストします。





シンボルライブラリの機能の1つは、UTF-32のシンボルコードをそのクラスに効率的にマップすることです。 この機能を実装するには、 UnicodeData.txtファイルを使用すると便利です。 このファイルには、標準のすべての文字の列挙と、それらの4バイトコード(16進表記)およびクラスが含まれています。 ファイルはマシンによる処理を目的としていますが、人間には理解可能です。 たとえば、スペース文字は次の形式の行で指定されます。

0020;SPACE;Zs;0;WS;;;;;N;;;;;
      
      







ファイルでは、「;」文字がフィールド区切り記号として使用されます。 したがって、10進数は次のように設定されます。

 0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;; 0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;; 0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;; 0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;; 0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;; 0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;; 0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;; 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;; 0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;; 0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;;
      
      







また、文字のいくつかの定義をリストします。

 0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061; 0042;LATIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;0062; 0043;LATIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;0063; 0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041 0062;LATIN SMALL LETTER B;Ll;0;L;;;;;N;;;0042;;0042 0063;LATIN SMALL LETTER C;Ll;0;L;;;;;N;;;0043;;0043
      
      







クラスLuおよびLlの文字については、対応する下位(上位)文字のコードも設定されることに注意してください。 これにより、ライブラリにレジスタ変換関数を実装できます。



シンボルライブラリの実装





シンボルライブラリは、UNICODE文字クラスの定義と、大文字または小文字への変換を実装しています。



クラスを定義するには、SymbolClass列挙子を使用します。

 enum SymbolClass { UPPERCASE_LETTER = 0x00000001, LOWERCASE_LETTER = 0x00000002, TITLECASE_LETTER = 0x00000004, CASED_LETTER = UPPERCASE_LETTER | LOWERCASE_LETTER | TITLECASE_LETTER, MODIFIER_LETTER = 0x00000008, OTHER_LETTER = 0x00000010, LETTER = CASED_LETTER | MODIFIER_LETTER | OTHER_LETTER, NONSPACING_MARK = 0x00000020, ...
      
      







列挙子要素は2の累乗で指定されるため、ビットフラグとして使用できます。 ライブラリの実装では、クラスに対応するビットが単位に設定されている各文字に4バイトの値が設定されます。 次に、特定のクラスに属するシンボルのチェックは、単に対応するビットの値です。

 template<SymbolClass class_name> inline bool Is(const SymbolCode& code) { return static_cast<uint32_t>(class_name) & GetSymbolClass(code); }
      
      







最も一般的に使用されるクラスには、対応する機能が実装されています。

 inline bool IsLetter(const SymbolCode& code) { return Is<LETTER>(code); } inline bool IsNumber(const SymbolCode& code) { return Is<NUMBER>(code); } inline bool IsPunctuation(const SymbolCode& code) { return Is<PUNCTUATION>(code); }
      
      







大文字/小文字に変換するには、ToLowerおよびToUpper関数が使用されます。 これらの機能は、文字だけでなく、他の文字にも適用できることに注意してください。 レジスタの概念を適用できない文字の場合、関数は入力で送信されたものと同じコードを返します。



技術的には、これらはすべて非常に効率的に実装されています。 構成段階で、Pythonで記述されたスクリプトを実行し、UnicodeData.txtファイルを読み取り、大文字と小文字の文字クラスに対して3つの配列が定義されているsymbols.cppファイルを生成します。 これらの配列は次のように宣言されます。

 namespace details { // The symbol tables declarations. extern uint32_t SYM_CLASS_TABLE[]; extern SymbolCode SYM_UPPER_TABLE[]; extern SymbolCode SYM_LOWER_TABLE[]; } // namespace details.
      
      







大文字と小文字への変換関数は単純に設定されます:

 inline SymbolCode ToLower(const SymbolCode& code) { return details::SYM_LOWER_TABLE[code]; } inline SymbolCode ToUpper(const SymbolCode& code) { return details::SYM_UPPER_TABLE[code]; }
      
      







文字クラスのセットを取得するには、次の関数が使用されます。

 inline const uint32_t& GetSymbolClass(const SymbolCode& code) { return details::SYM_CLASS_TABLE[code]; }
      
      







定義からわかるように、文字コードは配列のインデックスとして使用されるため、配列要素へのアクセスには追加コストは必要ありません。 各配列のサイズは、UnicodeData.txtで定義されている文字数によって制限されます。 現時点では、この数値は0x200000です。つまり、 各アレイはメモリ内で8 MBを占有し、合計で24 MBを占有します。 これは効率のための少額の料金のようです。



もちろん、ファイルでは、文字がUTF-32に格納されることはほとんどありません。1バイトに収まる文字コードを格納するために4バイトを使用するのは非効率的です。 ストレージには、「pre-unicode world」(CP1251、Koi8-rなど)から来たシングルバイトエンコーディングと、ファイル内の文字を効率的に保存するために特別に設計されたUTF-8エンコーディングが使用されます。 Strutextライブラリは、UTF-8の文字コードを分析するための強力なツールを提供します。 エンコードコンポーネントがこれを行います。



あとがき





テキストの記述とStrutextライブラリの開発の両方の主な動機の1つは、C ++ワードプロセッシングアプリケーションの開発での経験を他の開発者と共有したいという著者の願いでした。 ライブラリコードは、著者の職業経験の重要な具体例と考えることができます(著者は、このコードが彼の経験をすべて使い果たすことはないことを望んでいます)。



もちろん、「共有」という動詞は2つの側面を意味します。1つは共有するもの、もう1つはこの部門を受け入れたいというものです。 最初の面に問題がないことが誰にも明らかな場合、この出版物を含めて、2番目の面の存在を発見することを意図しています。 テキストへの応答がある場合、作成者は一生懸命働いて、Strutextライブラリの他のコンポーネントを説明する準備ができています。



All Articles