2012-03-14 5 views
5

私は別の答えに便利な機能を見つけました。誰かがそれが何をしているのか、それが信頼できるものかを私に説明することができるのだろうかと思います。私はmb_detect_encoding()を使用していましたが、Linux OS上のISO8859-1ファイルから読み込むときには書き込まれませんでした。PHPでのUTF8文字列のテストは、これは信頼できる方法ですか?

この機能は、私がテストしたすべてのケースで機能するようです。ここで

は疑問である:ここではGet file encoding

は関数である。

function isUTF8($string){ 
    return preg_match('%(?: 
    [\xC2-\xDF][\x80-\xBF]        # non-overlong 2-byte 
    |\xE0[\xA0-\xBF][\x80-\xBF]               # excluding overlongs 
    |[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}      # straight 3-byte 
    |\xED[\x80-\x9F][\x80-\xBF]               # excluding surrogates 
    |\xF0[\x90-\xBF][\x80-\xBF]{2}    # planes 1-3 
    |[\xF1-\xF3][\x80-\xBF]{3}                  # planes 4-15 
    |\xF4[\x80-\x8F][\x80-\xBF]{2}    # plane 16 
   )+%xs', $string); 
} 

これはUTF8文字列を検出するための信頼できる方法はありますか? 正確には何をしていますか? より堅牢にすることはできますか?

+2

:ここ

は文字列がUTF-8である場合を教えてくれる元、正しく動作して(私がテストしてみた)関数です.net/manual/en/function.mb-detect-encoding.php)? – summea

+1

この関数は "1"の文字列はutf8ではないと考えていることを言いたいと思いますが(明示的にはasciiですが、まだutf8に組み込む必要があります) – zerkms

+0

@summeaすべて? –

答えて

6

の文字列のエンコードを知っていない場合、ある程度の精度でエンコードを推測することは不可能です。そのため、mb_detect_encodingはうまくいきません。文字列のエンコーディングが何であるかを知っていれば、が入っていれば、それがmb_check_encodingを使ってそのエンコーディング内の有効な文字列であるかどうかを調べることができます。それは多かれ少なかれあなたの正規表現は、おそらくもう少し包括的に何をしますか? 「このバイト列はUTF-8で有効ですか?」という質問に答えることができます。は、はいかいいえが明確です。実際にはという文字列がそのエンコーディングでコード化されたであることを意味するとは限りません。たとえば、すべての8ビットを使用するシングルバイトエンコーディングと、8ビットを使用する他のシングルバイトエンコーディングを区別することは不可能です。しかしUTF-8 と区別できるはずですが、有効なUTF-8バイトシーケンスであるLatin-1エンコードされた文字列などを生成することもできます。

要するに、確かに知る方法はありません。 UTF-8が必要な場合は、受信したバイトシーケンスがUTF-8で有効かどうかを確認してから、文字列をUTF-8として安全に処理できます。それ以外にはあなたができることはほとんどありません。

+0

文字列が有効なUTF-8文字列かどうかをテストできますが、 "Hello World"もASCIIであってもそのテストに合格しますが、有効なラテン文字であるかどうかを確認する方法で検証できます-1またはasciiで、UTF-8ではない? –

+1

"Hello World"は有効なASCII *および* Latin-1 *および* UTF-8です! – deceze

+0

UTF-8ならテストしてみましたが、有効なASCIIのテストに失敗した場合はASCII、それ以外はUTF-8と仮定します。 UTF-8の場合はZipファイルのヘッダ構造にフラグを設定する必要があるため、これが必要でしたが、そうでなければこれを行うべきではありません。 –

0

文字列に有効なUTF-8コードポイントに対応するバイトシーケンスがあるかどうかをチェックするだけです。ただし、UTF-8のASCII互換サブセットであるシーケンス0x00-0x7Fにフラグを立てません。

編集:ちなみに、mb_detect_encoding()が「正しく動作しませんでした」という理由は、Latin-1でエンコードされたファイルがUTF-8で有効なASCII互換のサブセットのみを使用していたためですと推測しています。 mb_detect_encoding()がUTF-8としてフラグを立てることは当然のことであり、データが平易なASCIIの場合はUTF-8がLatin-1、ASCII、または無数の拡張ASCIIエンコーディング

+0

問題はさらにエンコードする必要があるため、エンコードする前に正確に何かを知る必要があります。そして、はい、それは拡張ASCIIセットの問題です。 –

0

文字列の一部が正式に有効なUTF-8シーケンスであるかどうかを検出し、1つのコード単位のエンコード文字(ASCIIのコードポイントを表す)は無視します。その関数がtrueを返すには、ASCII以外のUTF-8エンコード文字のように見える文字が1つあれば十分です。

0

これはあなたの質問に対する回答ではないかもしれませんが(おそらくそれは下記のアップデートを参照してください)、あなたの問題に対する答えかもしれません。彼らはすでにLatin1の、WIN1252、またはUTF8でエンコードされている場合はUTF8に文字列を変換するためのメソッドを持っている私のEncodingクラスに関係なく、チェックアウト、またはそれらの組み合わせ:

Encoding::toUTF8($text_or_array); 
Encoding::toWin1252($text_or_array); 
Encoding::toISO8859($text_or_array); 

// fixes UTF8 strings converted to UTF8 repeatedly: 
// "FÃÂédÃÂération" to "Fédération" 
Encoding::fixUTF8($text_or_array); 

https://stackoverflow.com/a/3479832/290221

機能の実行にバイトごとに変換が必要かどうかを調べてください。

更新:

はそれについてもう少し考えると、これは実際にあなたの質問への答えのようになります。

require_once('Encoding.php'); 

function validUTF8($string){ 
    return Encoding::toUTF8($string) == $string; 
} 

そしてここでは、Encodingクラスです: https://github.com/neitanod/forceutf8

+0

それはすべてのことが最良の推測に基づいて動作することができます。もし私が「F?d?c?ration」と書くことを意味したら?エンコーディングの問題を示すためにここのこのページのように。エンコーディングミストリートメントのためにテキストが不正になった場合は、そのテキストを修正する必要があります。 – deceze

+0

正確に。それで、最後の機能がtoUTF8()からそれ自身の機能に分離されている理由です。 コマンドラインプログラムでいくつかのファイルを修正するためにfixUTF8()を作成しました。ライブウェブサイト用ではありません。 それにもかかわらず、ライブウェブサイトではtoUTF8()を使用します。 –

+0

私はまた、実際に各バイトを個別にチェックする必要性を理解していません。混合エンコードされた文字列を期待していますか?もしそうなら、あなたの問題は他の場所にあります。エンコーディングは、あなたが実際に扱っていることを知る必要があるような性質のものです。文字列をブラックボックスとして扱うことはできません。* 1つのエンコーディングから*別のものにのみ変換することができます。あなたが探している結果を確実に得ることはできません。あなたのクラスはかなりの作業ですが、私は本当にそれを使用することをお勧めします。 – deceze

0

基本的には、いいえ。

  • 任意 UTF8文字列が有効な8ビットエンコーディング列(それが意味不明を生成する場合であっても)です。一方
  • 、拡張(128+)文字で最も 8ビットのエンコードされた文字列は、他のランダムなバイトシーケンスとして、彼らはことが起こるかもしれませんない有効UTF8ですが、。
  • また、ASCIIテキストのの有効なUTF8なので、mb_detect_encodingというのは実際そうです。また、ASCIIテキストをUTF8として使用しても問題はありません。それがUTF8が最初に働く理由です。

私の知る限り理解し、あなたが供給機能は、このように、この関数ははるかに悪化失火かもしれないが、それはUTF8と同様のことが起こるいくつかの配列を含むだけのことを、文字列の妥当性をチェックしません。 。この関数mb_detect_encodingの両方を厳密なモードで使用し、お互いの誤検出を相殺することを望むかもしれません。

テキストが非ラテンアルファベットで書かれている場合、マルチバイトエンコーディングを検出する「スマートな」方法は、同じビットで始まる同じ大きさのバイトチャンクのシーケンスを探すことです。たとえば、ロシア語の単語「привет」は次のようになります。

11010000 10111111 
11010001 10000000 
11010000 10111000 
11010000 10110010 
11010000 10110101 
11010001 10000010 

これは、しかし、ラテン語ベースのアルファベット(と、おそらく、中国)のために動作しません。

0

問題の機能(ユーザーpilifがリンクされ、質問に掲示1)はPHPマニュアルにmb_detect_encoding()ページthis commentから取られているように見えます:著者の状態として

、機能があるだけで「文字列 UTF-8文字が含まれているかどうかをチェックする」ことを意味し、「UTF-8範囲の非ASCIIマルチバイトシーケンス」のみを検索します。したがって、文字列に英文のような単純なASCII文字が含まれている場合は、関数はfalse(実際にはゼロ)を返します。これはおそらくあなたが望むものではありません。

彼の機能は、実際には文字列がUTF-8であるかどうかを確認するための同じページのthis previous commentの別の機能に基づいており、W3Cの誰かによって作成されたthis regular expressionに基づいていました。 // PHP: `mb_detect_encoding`(HTTPのようなものを使用しないのはなぜ

// Returns true if $string is valid UTF-8 and false otherwise. 
function is_utf8($string) { 

    // From http://w3.org/International/questions/qa-forms-utf-8.html 
    return preg_match('%^(?: 
      [\x09\x0A\x0D\x20-\x7E]   # ASCII 
     | [\xC2-\xDF][\x80-\xBF]    # non-overlong 2-byte 
     | \xE0[\xA0-\xBF][\x80-\xBF]  # excluding overlongs 
     | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte 
     | \xED[\x80-\x9F][\x80-\xBF]  # excluding surrogates 
     | \xF0[\x90-\xBF][\x80-\xBF]{2}  # planes 1-3 
     | [\xF1-\xF3][\x80-\xBF]{3}   # planes 4-15 
     | \xF4[\x80-\x8F][\x80-\xBF]{2}  # plane 16 
    )*$%xs', $string); 

} // function is_utf8 
+0

ところで、 'mb_detect_encoding()'を使用する際の1つの問題は、Mac OS Roman(または "macintosh")文字セットをサポートしていないことです。これはまだOS Xで多少一般的に使用されています。 UTF-8として – jnrbsn

関連する問題