web-dev-qa-db-ja.com

UnicodeのFlex(レクサー)サポート

最新バージョンのflexがUnicodeをサポートしているかどうか疑問に思っていますか?

もしそうなら、どのようにパターンを使用して漢字を一致させることができますか?

詳細: 正規表現を使用してutf-8エンコーディングの漢字と一致させます

22
xiaohan2012

現時点では、flexは8ビットスキャナーのみを生成するため、基本的にUTF-8の使用が制限されます。したがって、パターンがある場合:

肖晗   { printf ("xiaohan\n"); }

パターンと入力のバイトシーケンスは同じであるため、期待どおりに機能します。もっと難しいのはキャラクタークラスです。文字表または晗のいずれかに一致させたい場合は、次のように書くことはできません。

[肖晗]   { printf ("xiaohan/2\n"); }

これは、6バイトの0xe8、0x82、0x96、0xe6、0x99、および0x97のそれぞれに一致するためです。つまり、実際には、入力として肖晗を指定すると、パターンは6回一致します。したがって、この単純なケースでは、パターンを(肖|晗)に書き直す必要があります。

範囲については、Hans Abergが Haskellのツール を作成しました。これはこれらを8ビットパターンに変換します。

Unicode> urToRegU8 0 0xFFFF
[\0-\x7F]|[\xC2-\xDF][\x80-\xBF]|(\xE0[\xA0-\xBF]|[\xE1-\xEF][\x80-\xBF])[\x80-\xBF]
Unicode> urToRegU32 0x00010000 0x001FFFFF
\0[\x01-\x1F][\0-\xFF][\0-\xFF]
Unicode> urToRegU32L 0x00010000 0x001FFFFF
[\x01-\x1F][\0-\xFF][\0-\xFF]\0

これはきれいではありませんが、機能するはずです。

19
Tim Landscheidt

FlexはUnicodeをサポートしていません。ただし、Flexは「8ビットクリーン」バイナリ入力をサポートしています。したがって、UTF-8に一致する字句パターンを記述できます。これらのパターンは、入力言語の特定の字句領域(識別子、コメント、文字列リテラルなど)で使用できます。

これは、ソース言語がASCII/UTF-8で記述されている(他のエンコーディングはサポートされていない、期間)ことを実装のユーザーに表明できる可能性がある一般的なプログラミング言語でうまく機能します。

スキャナーが任意のエンコーディングのテキストを処理する必要がある場合、このアプローチは機能しません。また、Unicode要素専用の字句規則を表現する必要がある場合も(非常にうまく機能しません)。つまりスキャナー自体にUnicode文字とUnicode正規表現が必要です。

Lexルールを使用してUTF-8バイトを含むパターンを認識できるという考え方です(そして、おそらくyytextを取得し、UTF-8から変換するか、少なくとも検証します)。

実用的な例については、TXR言語のソースコード、特にこのファイルを参照してください。 http://www.kylheku.com/cgit/txr/tree/parser.l

このセクションまで下にスクロールします。

ASC     [\x00-\x7f]
ASCN    [\x00-\t\v-\x7f]
U       [\x80-\xbf]
U2      [\xc2-\xdf]
U3      [\xe0-\xef]
U4      [\xf0-\xf4]

UANY    {ASC}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}
UANYN   {ASCN}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U} 
UONLY   {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}

ご覧のとおり、ASCII文字とUTF-8の開始バイトと継続バイトに一致するパターンを定義できます。UTF-8は字句表記であり、これは字句解析ジェネレーターです。 ... 問題ない!

いくつかの説明:UANYは任意の文字に一致することを意味し、シングルバイトASCIIまたはマルチバイトUTF-8。UANYNUANYのように意味します。ただし、改行と一致しません。これは、#から行末までの国際テキストを含むコメントなど、行をまたがらないトークンに役立ちます。UONLYは、 ASCII 1ではなくUTF-8拡張文字。これは、特定のASCII文字(改行だけでなく)を除外する必要があるLexルールを作成する場合に役立ちます)しかし、すべての拡張文字は問題ありません。

免責事項:スキャナーのルールはutf8_dup_fromという関数を使用して、yytextをUnicodeコードポイントを含むワイド文字列に変換することに注意してください。その機能は堅牢です。シーケンスが長すぎる、無効なバイトなどの問題を検出し、適切に処理します。つまりこのプログラムは、基本的な字句認識を行うためだけに、検証と変換を行うためにこれらのLexルールに依存していません。これらのルールは、長すぎる形式(ASCII数バイトを使用してエンコードされたコードなど)を有効な構文として認識しますが、変換関数はそれらを適切に処理します。いずれにせよ、UTF-は期待していません。とにかくそれを実行するにはソースコードを信頼する必要があるため、プログラムソースコードの8つの関連するセキュリティ問題(ただし、プログラムによって処理されるデータは信頼されない可能性があります!)信頼できないUTF-8データ用のスキャナーを作成している場合は、ケア!

18
Kaz

最新バージョンのflexがUnicodeをサポートしているかどうか疑問に思っていますか?

もしそうなら、どのようにパターンを使用して漢字を一致させることができますか?

Flex互換の字句解析プログラムで漢字やその他のUnicodeコードポイントとパターンを一致させるには、C++の場合は RE/flex字句解析プログラム を使用できます。

RE/flexは完全なUnicode 12標準を安全にサポートし、UTF-8ハックを必要とせずにUTF-8、UTF-16、およびUTF-32入力ファイルを受け入れますUTF-16/32入力もサポートできません。

また、Flexを使用したUTF-8ハックでは、RE/flexで完全にサポートされている[肖晗]などのUnicode正規表現を記述できません。

Bisonとシームレスに連携して、レクサーとパーサーを構築します。

実際、RE/flexを使用すると、次のようなlexer.l仕様でUTF-8ベースの正規表現として任意のUnicodeパターンを記述できます。

%option flex unicode
%%
[肖晗]   { printf ("xiaohan/2\n"); }
%%

これにより、UTF-8、UTF-16、およびUTF-32ファイルを自動的にスキャンするレクサーが生成されます。 UTF標準化に従って、UTF-16/32入力の場合、入力にはUTF BOMが必要ですが、UTF-8BOMはオプションです。

グローバル%option unicodeを使用してUnicodeを有効にし、%option flexを使用してFlex仕様を指定できます。ローカル修飾子(?u:)を使用して、Unicodeを単一のパターンに制限できます(したがって、他のすべてはFlexの場合と同様にASCII/8ビットのままです)。

%option flex
%%
(?u:[肖晗])   { printf ("xiaohan/2\n"); }
(?u:\p{Han})  { printf ("Han character %s\n", yytext); }
.             { printf ("8-bit character %d\n", yytext[0]); }
%%

オプションflexはFlex互換性を有効にするため、yytextyylengECHOなどを使用できます。 flexオプションがない場合、RE/flexはレクサーメソッド呼び出しを予期します:text()(またはstd::stringおよびstd::wstringの場合はstr()およびwstr())、size()(またはワイド文字の長さの場合はwsize())、およびecho()。 RE/flexメソッド呼び出しはよりクリーンなIMHOであり、ワイド文字操作が含まれています。

3
Dr. Alex RE