2011-05-20 30 views
7

cómo puedo convertir un wchar_t ('9') en un dígito en forma de int (9)?Convierte wchar_t en int

tengo el siguiente código donde puedo comprobar si peek o no es un dígito:

if (iswdigit(peek)) { 
    // store peek as numeric 
} 

¿Puedo restar '0' o hay algunos detalles Unicode debería preocuparse?

+1

¿Tiene un carácter '9' y quiere convertirlo en el dígito '9'? –

+0

@Daren Sí, esa es la idea. –

+0

Si solo tenía ASCII, también podría hacer 'peek & 0xF' – Raze

Respuesta

4

Si la pregunta es solo '9' (o uno de los dígitos romanos ), solo restar '0' es la solución correcta. Si le preocupa algo por lo que iswdigit devuelve distinto de cero, sin embargo, el problema puede ser mucho más complejo. El estándar dice que iswdigit devuelve un valor distinto de cero si su argumento es "un código de dígitos de dígitos decimales [en el actual local]". Lo cual es impreciso, y lo deja a la configuración regional a definir exactamente lo que significa. En la configuración regional "C" o la configuración regional "Posix" , el estándar "Posix", al menos, garantiza que solo los dígitos romanos de cero a nueve se consideran dígitos decimales (si lo entiendo correctamente), entonces si re en la configuración regional "C" o "Posix" , simplemente restando '0' debería funcionar.

Presumiblemente, en una configuración regional Unicode, este sería cualquier carácter que tenga la categoría general Nd. Hay un número de estos.La solución más segura sería simplemente para crear algo como (variables aquí con duración estática):

wchar_t const* const digitTables[] = 
{ 
    L"", 
    L"\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669", 
    // ... 
}; 

//!  \return 
//!   wch as a numeric digit, or -1 if it is not a digit 
int asNumeric(wchar_t wch) 
{ 
    int result = -1; 
    for (wchar_t const* const* p = std::begin(digitTables); 
      p != std::end(digitTables) && result == -1; 
      ++ p) { 
     wchar_t const* q = std::find(*p, *p + 10, wch); 
     if (q != *p + 10) { 
      result = q - *p; 
    } 
    return result; 
} 

Si usted va esta manera:

  1. que sin duda quiere descargar el archivo desde UnicodeData.txt el consorcio Unicode ("Uncode Character Database" — esta página tiene unos enlaces a la vez los datos de archivos Unicode y un explination de las codificaciones utilizadas en ella), y
  2. posiblemente escriba un analizador simple de este archivo para extraer la información automáticamente (p. cuando hay una nueva versión de Unicode) — el archivo está diseñado para el análisis programático simple .

Por último, tenga en cuenta que las soluciones basadas en ostringstream y istringstream (esto incluye boost::lexical_cast) no se trabajo, ya que las conversiones se utilizan en corrientes se definen solamente utilizan los dígitos romanos. (Por otro lado, podría ser razonables para restringir su código para sólo los dígitos romanos. En cuyo caso, la prueba se convierte en if (wch >= L'0' && wch <= L'9'), y la conversión se realiza restando simplemente L'0' — siempre suponiendo que el de la codificación nativa de las constantes de carácter ancho en su compilador son Unicode (el caso, soy bastante seguro, tanto de VC++ como de g ++). O simplemente asegúrese de que la configuración regional sea "C" (o "Posix", en una máquina Unix).

EDIT: se me olvidó mencionar:., si está haciendo ningún tipo de programación seria Unicode, debe buscar en ICU Manejo Unicod e correctamente es extremadamente no trivial, y que han una gran cantidad de funcionalidad ya implementado.

+0

+1 Gracias por la respuesta integral :) No estoy haciendo ninguna programación Unicode seria. Solo quería que fuera consciente de Unicode, pero supongo que es una tarea muy difícil de hacer correctamente. –

+1

Depende del nivel de conciencia de Unicode que desee. C++ y Java son oficialmente compatibles con Unicode, pero aún requieren que las constantes numéricas estén en números romanos; ellos son Unicode-awareness está limitado a permitir caracteres Unicode en símbolos y en cadenas y caracteres literales (y comentarios). Creo que para muchos programas, algo así es suficiente conocimiento de Unicode. –

5

mirar en la clase atoi de funciones: http://msdn.microsoft.com/en-us/library/hc25t012(v=vs.71).aspx

Especialmente _wtoi(const wchar_t *string); parece ser lo que usted está buscando. Usted tendría que asegurarse de que su wchar_t está correctamente terminada en nulo, aunque, por lo que intentar algo como esto:

if (iswdigit(peek)) { 
    // store peek as numeric 
    wchar_t s[2]; 
    s[0] = peek; 
    s[1] = 0; 
    int numeric_peek = _wtoi(s); 
} 
+0

He visto esos, pero parece un poco estúpido convertirlo en' cadena', y después de eso, convertirlo a 'int'. Pero si esa es la forma habitual de hacerlo, supongo que lo haré :) –

+0

Cierto, pero ¿de verdad quieres duplicar este tipo de lógica? Deberías asegurarte de que sabes todo lo que hay que saber sobre Unicode. O al menos lo suficiente como para estar seguro de que no estás arruinando. Yo personalmente no me arriesgaría. –

+0

No lo haré tampoco. Solo pensé que había un método para hacerlo. Veo que la biblioteca de impulso lo hace. +1 –

0

Para la mayoría de los propósitos que sólo puede restar el código de '0'.

Sin embargo, el artículo de Wikipedia en Unicode numerials menciona que los dígitos decimales están representados en 23 bloques separados (incluidos dos en árabe).

Si no está preocupado por eso, simplemente resta el código para '0'.

+0

Si esos números Unicode son reconocidos por 'iswdigit' entonces podría romper mi código. Así que supongo que tengo que preocuparse por ese dígito :) –

+0

Unicode romper su código si y sólo si su localización actual tiene algo de la configuración regional que no utiliza los números estándar/Inglés ASCII. – Raze

1

Usted podría utilizar boost::lexical_cast:

const wchar_t c = '9'; 
int n = boost::lexical_cast<int>(c); 
+0

+1 Exactamente lo que estaba buscando –

+2

Esto es una exageración escandalosa. Detrás de las escenas, que está creando un 'std :: ostreamstring' para convertir el' 'wchar_t' en un std :: string', a continuación, un' std :: istringstream' para convertir el 'std :: string' en un int , cuando todo lo que se necesita es una simple resta. –

+0

Simplemente usaría if (peek> = L'0 '&& peek <= L'9') –

1

pesar MSDN documentation, una simple prueba sugieren que los rendimientos no sólo guardabosques L'0'-L'9' verdadera.

for(wchar_t i = 0; i < 0xFFFF; ++i) 
{ 
    if (iswdigit(i)) 
    { 
     wprintf(L"%d : %c\n", i, i); 
    } 
} 

Eso significa que L'0 'substraction probablemente no funcione como es de esperar.

+0

¿En qué localidad? 'iswdigit' es específico de la configuración regional, por lo que no puede hacer ninguna declaración al respecto sin especificar la configuración regional. –

+0

inglés o alemán. No puedo decirlo con seguridad Tengo un cuadro en inglés con algunas configuraciones alemanas. –

+0

Eso no afecta necesariamente su configuración regional en el código. Todos los programas comienzan en la configuración regional "C". –