En primer lugar, el uso de std::cin >> name
se fallar si el usuario ingresa John Smith
porque >>
divide la entrada en caracteres de espacios en blanco. Debe utilizar std::getline()
para obtener el nombre:
std::getline(std::cin, name);
Aquí vamos ...
Hay un número de maneras de comprobar que una cadena contiene sólo caracteres alfabéticos. La más sencilla es probablemente s.find_first_not_of(t)
, que devuelve el índice del primer carácter en s
que no está en t
:
bool contains_non_alpha
= name.find_first_not_of("abcdefghijklmnopqrstuvwxyz") != std::string::npos;
que rápidamente se vuelve muy complicada, sin embargo. Para que coincida con los caracteres alfabéticos en mayúsculas, debe agregar 26 caracteres más a esa cadena. En su lugar, es posible que desee utilizar una combinación de find_if
de la cabecera <algorithm>
y std::isalpha
de <cctype>
:
#include <algorithm>
#include <cctype>
struct non_alpha {
bool operator()(char c) {
return !std::isalpha(c);
}
};
bool contains_non_alpha
= std::find_if(name.begin(), name.end(), non_alpha()) != name.end();
find_if
búsquedas al alcance de un valor que coincide con un predicado, en este caso un funtor non_alpha
que devuelve si su argumento es un personaje no alfabético Si find_if(name.begin(), name.end(), ...)
devuelve name.end()
, no se encontró ninguna coincidencia.
¡Pero aún hay más!
Para hacer esto como una sola línea, puede utilizar los adaptadores del <functional>
cabecera:
#include <algorithm>
#include <cctype>
#include <functional>
bool contains_non_alpha
= std::find_if(name.begin(), name.end(),
std::not1(std::ptr_fun((int(*)(int))std::isalpha))) != name.end();
El std::not1
produce un objeto de función que devuelve la inversa lógica de su entrada; suministrando un puntero a una función con std::ptr_fun(...)
, podemos decir std::not1
para producir la inversa lógica de std::isalpha
. El molde (int(*)(int))
está allí para seleccionar la sobrecarga de std::isalpha
que toma un int
(tratado como un carácter) y devuelve un int
(tratado como un booleano).
O, si se puede utilizar un compilador de C++ 11, utilizando una lambda limpia esto mucho:
#include <cctype>
bool contains_non_alpha
= std::find_if(name.begin(), name.end(),
[](char c) { return !std::isalpha(c); }) != name.end();
[](char c) -> bool { ... }
denota una función que acepta un carácter y devuelve un bool
. En nuestro caso, podemos omitir el tipo de devolución -> bool
porque el cuerpo de la función consiste solamente en una declaración return
. Esto funciona igual que en los ejemplos anteriores, excepto que el objeto de función se puede especificar mucho más sucintamente.
y (casi) por último ...
En C++ 11 también se puede usar una expresión regular para llevar a cabo el partido:
#include <regex>
bool contains_non_alpha
= !std::regex_match(name, std::regex("^[A-Za-z]+$"));
Pero, por supuesto ...
Ninguna de estas soluciones ¡aborda el problema de la codificación de locale o de caracteres! Para una versión independiente de la Localidad de isalpha()
, que había necesidad de utilizar el encabezado de C++ <locale>
:
#include <locale>
bool isalpha(char c) {
std::locale locale; // Default locale.
return std::use_facet<std::ctype<char> >(locale).is(std::ctype<char>::alpha, c);
}
Lo ideal sería utilizar char32_t
, pero ctype
no parece ser capaz de clasificar, por lo que estamos atascado con char
. Por suerte para nosotros podemos bailar completamente sobre el tema de la configuración regional, porque probablemente solo le interesen las letras en inglés. Hay una útil biblioteca de solo encabezado llamada UTF8-CPP que nos permitirá hacer lo que necesitamos hacer de una forma más segura para la codificación. Primero definimos nuestra versión de isalpha()
que utiliza UTF-32 puntos de código:
bool isalpha(uint32_t c) {
return (c >= 0x0041 && c <= 0x005A)
|| (c >= 0x0061 && c <= 0x007A);
}
entonces podemos utilizar el adaptador utf8::iterator
para adaptar el basic_string::iterator
de octetos en UTF-32 puntos de código:
#include <utf8.h>
bool contains_non_alpha
= std::find_if(utf8::iterator(name.begin(), name.begin(), name.end()),
utf8::iterator(name.end(), name.begin(), name.end()),
[](uint32_t c) { return !isalpha(c); }) != name.end();
Para un mejor rendimiento a costa de la seguridad, se puede utilizar utf8::unchecked::iterator
:
#include <utf8.h>
bool contains_non_alpha
= std::find_if(utf8::unchecked::iterator(name.begin()),
utf8::unchecked::iterator(name.end()),
[](uint32_t c) { return !isalpha(c); }) != name.end();
Esto se producirá un error en alguna inpu no válido t.
El uso de UTF8-CPP de esta manera asume que la codificación del host es UTF-8, o una codificación compatible como ASCII. En teoría, esta sigue siendo una solución imperfecta, pero en la práctica funcionará en la gran mayoría de las plataformas.
¡Espero que esta respuesta finalmente se haya completado!
Si esto es tarea ... debe marcarse como tal. –
¿Cuál es tu pregunta? ¿Su código está equivocado o le falta algo? En ese caso, ¿qué? –
'* it'. Por cierto, inténtelo con un diseño dvorak. –