(Estoy asumiendo que estás en Windows, ya que el uso U + FEFF como firma en UTF-8-files es sobre todo una cosa de Windows y simplemente se debe evitar en otro lugar)
se podían abrir el archivo como un archivo UTF-8 y luego verifique si el primer carácter es U + FEFF. Puede hacer esto abriendo un fstream basado en caracteres normales y luego usar wbuffer_convert para tratarlo como una serie de unidades de código en otra codificación. VS2010 todavía no tiene un gran soporte para char32_t, por lo que lo siguiente usa UTF-16 en wchar_t.
std::fstream fs(filename);
std::wbuffer_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> wb(fs.rdbuf());
std::wistream is(&wb);
// if you don't do this on the stack remember to destroy the objects in reverse order of creation. is, then wb, then fs.
std::wistream::int_type ch = is.get();
const std::wistream::int_type ZERO_WIDTH_NO_BREAK_SPACE = 0xFEFF
if(ZERO_WIDTH_NO_BREAK_SPACE != ch)
is.putback(ch);
// now the stream can be passed around and used without worrying about the extra character in the stream.
int i;
readFromStream<int>(is,i);
Recuerde que esto debe hacerse en la secuencia de archivo como un todo, no dentro ReadFromFile en su stringstream, porque ignorando U + FEFF sólo debe hacerse si es el primer personaje en todo el archivo, si es todas. No debería hacerse en ningún otro lado.
Por otro lado, si eres feliz usando una corriente basada en carbón y que quiere es ignorar U + FEFF si están presentes, James Kanze sugerencia parece bien, así que aquí es una implementación:
std::fstream fs(filename);
char a,b,c;
a = fs.get();
b = fs.get();
c = fs.get();
if(a!=(char)0xEF || b!=(char)0xBB || c!=(char)0xBF) {
fs.seekg(0);
} else {
std::cerr << "Warning: file contains the so-called 'UTF-8 signature'\n"
}
Además, si desea utilizar wchar_t
internamente, las facetas codecvt_utf8_utf16
y codecvt_utf8
tienen un modo que puede consumir 'listas de materiales' para usted. El único problema es que wchar_t
es ampliamente reconocido como inútil en estos días * y por lo tanto, probablemente no deberías hacer esto.
std::wifstream fin(filename);
fin.imbue(std::locale(fin.getloc(), new std::codecvt_utf8_utf16<wchar_t, 0x10FFFF, std::consume_header));
* wchar_t
no sirve para nada, ya que se especifica a hacer una sola cosa; proporcionar un tipo de datos de tamaño fijo que pueda representar cualquier punto de código en el repertorio de caracteres de un lugar. No proporciona una representación común entre locales (es decir, el mismo valor wchar_t
puede ser personajes diferentes en diferentes lugares por lo que no necesariamente se puede convertir a wchar_t
, cambiar a otro local, y luego convertir de nuevo a char
con el fin de hacer iconv
- al igual que las conversiones de codificación.)
La representación de tamaño fijo en sí no tiene ningún valor por dos razones; primero, muchos puntos de código tienen significados semánticos y, por lo tanto, entender el texto significa que debe procesar múltiples puntos de código de todos modos.En segundo lugar, algunas plataformas como Windows usan UTF-16 como la codificación wchar_t
, lo que significa que un solo wchar_t
ni siquiera es necesariamente un valor de punto de código. (Si el uso de UTF-16 de esta manera es incluso compatible con el estándar es ambiguo. El estándar requiere que cada carácter admitido por una configuración regional sea representable como un único valor wchar_t
; Si ninguna configuración regional admite ningún carácter fuera del BMP, entonces UTF-16 podría ser visto como conforme.)
¿Quiere decir la UTF-8 BOM? Eso es muy arcano ... –