2010-05-21 6 views
7

Me gustaría detectar la codificación de algunos textos (usando PHP). Para ese propósito, uso la función mb_detect_encoding().Extraño comportamiento de mb_detect_order() en PHP

El problema es que la función devuelve resultados diferentes si cambio el orden de posibles codificaciones con la función mb_detect_order().

Considere el siguiente ejemplo

$html = <<< STR 
ちょっとのアクセスで落ちてしまったり、サーバー障害が多いレンタルサーバーを選ぶとあなたのビジネス等にかなりの影響がでてしまう可能性があります。特に商売をされている個人の方、法人の方は気をつけるようにしてください 
STR; 
mb_detect_order(array('UTF-8','EUC-JP', 'SJIS', 'eucJP-win', 'SJIS-win', 'JIS', 'ISO-2022-JP','ISO-8859-1','ISO-8859-2')); 
$originalEncoding = mb_detect_encoding($str); 
die($originalEncoding); // $originalEncoding = 'UTF-8' 

Sin embargo, si se cambia el orden de las codificaciones en mb_detect_order() los resultados serán diferentes:

mb_detect_order(array('EUC-JP','UTF-8', 'SJIS', 'eucJP-win', 'SJIS-win', 'JIS', 'ISO-2022-JP','ISO-8859-1','ISO-8859-2'));   
die($originalEncoding); // $originalEncoding = 'EUC-JP' 



Así que mis preguntas son:
¿Por qué está sucediendo eso?
¿Hay alguna forma en PHP para detectar correctamente y sin ambigüedades la codificación de texto?

Respuesta

5

Eso es lo que esperaría que sucediera.

El algoritmo de detección probablemente solo sigue intentando, en orden, las codificaciones que especificó en mb_detect_order y luego devuelve la primera en la que el bytestream sería válido.

Algo más inteligente requiere métodos estadísticos (creo que el aprendizaje automático se usa comúnmente).

EDITAR: ver p. this article para métodos más inteligentes.

Debido a su importancia, la detección automática de caracteres ya está implementada en las principales aplicaciones de Internet, como Mozilla o Internet Explorer. Son muy precisos y rápidos, pero la implementación aplica muchos conocimientos específicos del dominio caso por caso. A diferencia de sus métodos, apuntamos a un algoritmo simple que se puede aplicar uniformemente a cada conjunto de caracteres, y el algoritmo se basa en técnicas de aprendizaje de máquina estándar bien establecidas. También estudiamos la relación entre el lenguaje y la detección de juegos de caracteres, y comparamos algoritmos basados ​​en bytes y algoritmos basados ​​en caracteres. Usamos Naive Bayes (NB) y Support Vector Machine (SVM).

+0

muchas gracias! – Termos

5

Realmente no. Las diferentes codificaciones suelen tener grandes áreas de superposición, y si la cadena que está probando existe dentro de esa superposición, ambas codificaciones son aceptables.

Por ejemplo, utf-8 e ISO-8859-1 son los mismos para las letras a-z. La cadena "hola" tendría una secuencia idéntica de bytes en ambas codificaciones.

Esto es exactamente por qué hay una función mb_detect_order() en primer lugar, ya que le permite decir lo que preferiría que ocurra cuando ocurran estos enfrentamientos. ¿Te gustaría "hola" ser utf-8 o ISO-8859-1?

+0

Supongo que hay muchos símbolos que se superponen en 2 codificaciones diferentes. En caso afirmativo, ¿cómo puedo seleccionar la codificación que mejor se adapta a un texto? En otras palabras, "¿cómo selecciono una codificación con la que se puede codificar un texto en particular sin pérdida de datos?" – Termos

+0

Optaría por la codificación más flexible primero y la última más específica. Por lo tanto, preferiría utf-8, ya que codificará texto en japonés, además de todos los demás idiomas, mientras que algo como ISO-8859-1 podría parecer adecuado para una muestra de texto dada, podría tener problemas si quisiera agregar personajes no europeos. En realidad, si se trata de muchos juegos de caracteres internacionales diferentes y no se sabe con anticipación, ¿por qué intentarlo y detectarlo? Solo use algo que siempre funcionará. –

1

mb_detect_encoding mira la primera entrada del conjunto de caracteres en su mb_detect_order() y luego recorre su carácter de entrada $ html coincidente carácter por carácter, ya sea que ese carácter se encuentre dentro del conjunto válido de caracteres para el juego de caracteres. Si cada personaje coincide, entonces devuelve verdadero; si cualquier carácter falla, pasa al siguiente juego de caracteres en el mb_detect_order() e intenta de nuevo.

The wikipedia list of charsets es un buen lugar para ver los personajes que componen cada juego de caracteres.

Dado que estos valores de conjunto de caracteres se superponen (char x8fA1EF existe tanto en 'UTF-8' como en 'EUC-JP') se considerará una coincidencia aunque sea un personaje totalmente diferente en cada conjunto de caracteres. Entonces, a menos que alguno de los valores de caracteres exista en un conjunto de caracteres, pero no en otro, entonces mb_detect_encoding no puede identificar cuál de los conjuntos de caracteres es inválido; y devolverá el primer juego de caracteres de su lista de arreglos, que podría ser válido.

Que yo sepa, no existe una forma segura de identificar un juego de caracteres. El método de "mejor suposición" de PHP puede ser ayudado si tiene una idea razonable de qué conjuntos de caracteres es probable que encuentre, y ordene su lista de acuerdo con las brechas (caracteres no válidos) en cada conjunto de caracteres. La mejor solución es "conocer" el juego de caracteres. Si está raspando su html de otra página, busque el identificador del juego de caracteres en el encabezado de esa página.

Si realmente quiere ser inteligente, puede intentar e identificar el idioma en el que está escrito el html, tal vez usando trigramas o n-grams o similar como se describe en this article en PHP/ir.

2

Tenga en cuenta que mb_detect_encoding() no sabe en qué codificación están los datos. Puede ver una cadena, pero la función solo ve una secuencia de bytes. De acuerdo con esto, necesita adivinar cuál es la codificación, por ej. ASCII sería si los bytes están solo en el rango 0-127, UTF-8 sería si hay bytes ASCII y más de 128 bytes que existen solo en pares o más, y así sucesivamente.

Como se puede imaginar, dado el contexto, es bastante difícil detectar una codificación de manera confiable.

Me gusta rihk dijo, esto es para lo que la función mb_detect_order() es para - básicamente estás proporcionando tu mejor estimación de cuáles son los datos. ¿Trabajas con archivos UTF-8 con frecuencia? Entonces es probable que sus cosas no sean UTF-16, incluso si mb_detect_encoding() pudiera adivinarlo así.

Es posible que también desee comprobar Artefacto 's link para una vista más en profundidad.

caso Ejemplo: Internet Explorer utiliza algunos de codificación interesante conjeturar si no se especifica nada (@link, Sección: 'Para detectar automáticamente el idioma de un sitio web') que es causado comportamientos extraños en los sitios web que se llevaron a la codificación por hecho en el pasado. Probablemente puedas encontrar algunas cosas divertidas si buscas en Google. Es una buena vitrina de cómo incluso los métodos estadísticos pueden ser contraproducentes horriblemente, y por qué la codificación de adivinar en general es problemática.