¿Cómo detectar la encoding de caracteres de un archivo de texto?

Intento detectar qué encoding de caracteres se usa en mi archivo.

Intento con este código para obtener la encoding estándar

public static Encoding GetFileEncoding(string srcFile) { // *** Use Default of Encoding.Default (Ansi CodePage) Encoding enc = Encoding.Default; // *** Detect byte order mark if any - otherwise assume default byte[] buffer = new byte[5]; FileStream file = new FileStream(srcFile, FileMode.Open); file.Read(buffer, 0, 5); file.Close(); if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf) enc = Encoding.UTF8; else if (buffer[0] == 0xfe && buffer[1] == 0xff) enc = Encoding.Unicode; else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff) enc = Encoding.UTF32; else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76) enc = Encoding.UTF7; else if (buffer[0] == 0xFE && buffer[1] == 0xFF) // 1201 unicodeFFFE Unicode (Big-Endian) enc = Encoding.GetEncoding(1201); else if (buffer[0] == 0xFF && buffer[1] == 0xFE) // 1200 utf-16 Unicode enc = Encoding.GetEncoding(1200); return enc; } 

Mis cinco primeros bytes son 60, 118, 56, 46 y 49.

¿Hay un gráfico que muestra qué encoding coincide con esos primeros cinco bytes?

No puede depender de que el archivo tenga una lista de materiales. UTF-8 no lo requiere. Y las codificaciones que no son Unicode ni siquiera tienen una lista de materiales. Sin embargo, hay otras formas de detectar la encoding.

UTF-32

La lista de materiales es 00 00 FE FF (para BE) o FF FE 00 00 (para LE).

Pero UTF-32 es fácil de detectar incluso sin una lista de materiales. Esto se debe a que el rango del punto de código Unicode está restringido a U + 10FFFF, por lo que las unidades UTF-32 siempre tienen el patrón 00 {0x | 10} xx xx (para BE) o xx xx {0x | 10} 00 (para LE) . Si los datos tienen una longitud que es un múltiplo de 4 y sigue uno de estos patrones, puedes asumir que es UTF-32. Los falsos positivos son casi imposibles debido a la rareza de 00 bytes en codificaciones orientadas a bytes.

US-ASCII

Sin lista de materiales, pero no la necesitas. ASCII se puede identificar fácilmente por la falta de bytes en el rango 80-FF.

UTF-8

BOM es EF BB BF. Pero no puedes confiar en esto. Muchos de los archivos UTF-8 no tienen una lista de materiales, especialmente si se originaron en sistemas que no son de Windows.

Pero puede suponer con seguridad que si un archivo se valida como UTF-8, es UTF-8. Los falsos positivos son raros.

Específicamente, dado que los datos no son ASCII, la tasa de falsos positivos para una secuencia de 2 bytes es solo del 3,9% (1920/49152). Para una secuencia de 7 bytes, es menos del 1%. Para una secuencia de 12 bytes, es menos de 0.1%. Para una secuencia de 24 bytes, es menos de 1 en un millón.

UTF-16

BOM es FE FF (para BE) o FF FE (para LE). Tenga en cuenta que la BOM UTF-16LE se encuentra al comienzo de la BOM UTF-32LE, por lo tanto, primero consulte UTF-32.

Puede haber archivos UTF-16 sin una lista de materiales, pero sería muy difícil detectarlos. La única manera confiable de reconocer el UTF-16 sin una BOM es buscar pares sustitutos (D [8-B] xx D [CF] xx), pero los caracteres que no son BMP rara vez se usan para hacer que este enfoque sea práctico.

XML

Si su archivo comienza con los bytes 3C 3F 78 6D 6C (es decir, los caracteres ASCII “encoding= statement. Si está presente, entonces use esa encoding. Si está ausente, entonces asum UTF-8, que es la encoding XML predeterminada.

Si necesita soportar EBCDIC, también busque la secuencia equivalente 4C 6F A7 94 93.

En general, si tiene un formato de archivo que contiene una statement de encoding, busque esa statement en lugar de tratar de adivinar la encoding.

Ninguna de las anteriores

Hay cientos de otras codificaciones que requieren más esfuerzo para detectarlas. Recomiendo probar el detector de charset de Mozilla o un puerto .NET de él .

Si desea buscar una solución “simple”, puede encontrar útil esta clase que reuní:

http://www.architectshack.com/TextFileEncodingDetector.ashx

Primero realiza la detección de BOM automáticamente, y luego intenta diferenciar entre codificaciones Unicode sin BOM, frente a alguna otra encoding predeterminada (generalmente Windows-1252, incorrectamente etiquetada como Encoding.ASCII en .Net).

Como se señaló anteriormente, una solución “más pesada” que involucre a NCharDet o MLang puede ser más apropiada, y como noto en la página de descripción general de esta clase, lo mejor es proporcionar alguna forma de interactividad con el usuario si es posible, porque simplemente ¡no es posible una tasa de detección del 100%!

Use StreamReader y StreamReader para detectar la encoding por usted:

 using (var reader = new System.IO.StreamReader(path, true)) { var currentEncoding = reader.CurrentEncoding; } 

Y use identificadores de página de códigos https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx para cambiar la lógica dependiendo de ello.

Varias respuestas están aquí, pero nadie ha publicado un código útil.

Aquí está mi código que detecta todas las codificaciones que Microsoft detecta en Framework 4 en la clase StreamReader.

Obviamente debe llamar a esta función inmediatamente después de abrir la secuencia antes de leer cualquier otra cosa de la secuencia porque la lista de materiales es el primer byte en la secuencia.

Esta función requiere un Stream que pueda buscar (por ejemplo, un FileStream). Si tiene un Stream que no puede buscar, debe escribir un código más complicado que devuelva un búfer Byte con los bytes que ya se han leído pero que no son BOM.

 ///  /// UTF8 : EF BB BF /// UTF16 BE: FE FF /// UTF16 LE: FF FE /// UTF32 BE: 00 00 FE FF /// UTF32 LE: FF FE 00 00 ///  public static Encoding DetectEncoding(Stream i_Stream) { if (!i_Stream.CanSeek || !i_Stream.CanRead) throw new Exception("DetectEncoding() requires a seekable and readable Stream"); // Try to read 4 bytes. If the stream is shorter, less bytes will be read. Byte[] u8_Buf = new Byte[4]; int s32_Count = i_Stream.Read(u8_Buf, 0, 4); if (s32_Count >= 2) { if (u8_Buf[0] == 0xFE && u8_Buf[1] == 0xFF) { i_Stream.Position = 2; return new UnicodeEncoding(true, true); } if (u8_Buf[0] == 0xFF && u8_Buf[1] == 0xFE) { if (s32_Count >= 4 && u8_Buf[2] == 0 && u8_Buf[3] == 0) { i_Stream.Position = 4; return new UTF32Encoding(false, true); } else { i_Stream.Position = 2; return new UnicodeEncoding(false, true); } } if (s32_Count >= 3 && u8_Buf[0] == 0xEF && u8_Buf[1] == 0xBB && u8_Buf[2] == 0xBF) { i_Stream.Position = 3; return Encoding.UTF8; } if (s32_Count >= 4 && u8_Buf[0] == 0 && u8_Buf[1] == 0 && u8_Buf[2] == 0xFE && u8_Buf[3] == 0xFF) { i_Stream.Position = 4; return new UTF32Encoding(true, true); } } i_Stream.Position = 0; return Encoding.Default; } 

Debería leer esto: ¿Cómo puedo detectar la encoding / página de códigos de un archivo de texto?

Si su archivo comienza con los bytes 60, 118, 56, 46 y 49, entonces tiene un caso ambiguo. Podría ser UTF-8 (sin BOM) o cualquiera de las codificaciones de un solo byte como ASCII, ANSI, ISO-8859-1, etc.

Yo uso Ude que es un puerto C # del Detector de Caracteres Universal Mozilla. Es fácil de usar y brinda algunos resultados realmente buenos.