2011-09-30 11 views
14

come ho potuto testare una stringa contro solo caratteri validi come lettere az ...come testare una stringa per le lettere solo

string name; 

cout << "Enter your name" 
cin >> name; 

string letters = "qwertyuiopasdfghjklzxcvbnm"; 

string::iterator it; 

for(it = name.begin(); it = name.end(); it++) 
{ 
    size_t found = letters.find(it); 
} 
+4

Se questo è compito ... dovrebbe essere contrassegnato come tale. –

+0

Qual è la tua domanda? Il tuo codice è sbagliato o manca qualcosa? In tal caso, che cosa? –

+3

'* it'. btw anche provarlo con un layout di dvorak. –

risposta

3

STL modo:?

struct TestFunctor 
{ 
    bool stringIsCorrect; 
    TestFunctor() 
    :stringIsCorrect(true) 
    {} 

    void operator() (char ch) 
    { 
    if(stringIsCorrect && !((ch <= 'z' && ch >= 'a') || (ch <= 'Z' && ch >= 'A'))) 
     stringIsCorrect = false; 
    } 
} 

TestFunctor functor; 

for_each(name.begin(), name.end(), functor); 

if(functor.stringIsCorrect) 
    cout << "Yay"; 
+0

e se volessi includere uno spazio come parte del parametro test? Come lo faresti? – miatech

+0

sostituisci 'if (stringIsCorrect &&! ((Ch <= 'z' && ch> = 'a') || (ch <= 'Z' && ch> = 'A')))' con 'if (stringIsCorrect && ! ((ch <= 'z' && ch> = 'a') || (ch <= 'Z' && ch> = 'A') || (ch == ''))) ' – GreenScape

+1

Nota che la codifica come [EBCDIC] (https://en.wikipedia.org/wiki/EBCDIC) ha caratteri tra ''a'' e'' z'' che non sono lettere. – Jarod42

43

primo luogo, utilizzando std::cin >> name sarà fallire se l'utente immette John Smith perché >> divide l'input su caratteri di spaziatura. Si dovrebbe usare std::getline() per ottenere il nome:

std::getline(std::cin, name); 

Qui andiamo ...

Ci sono un certo numero di modi per controllare che una stringa contiene solo caratteri alfabetici. Il più semplice è probabilmente s.find_first_not_of(t), che restituisce l'indice del primo carattere di s che non è nel t:

bool contains_non_alpha 
    = name.find_first_not_of("abcdefghijklmnopqrstuvwxyz") != std::string::npos; 

che diventa rapidamente ingombrante, però. Per abbinare anche caratteri alfabetici maiuscoli, devi aggiungere altri 26 caratteri a quella stringa! Invece, si consiglia di utilizzare una combinazione di find_if dal <algorithm> intestazione e std::isalpha da <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 ricerche un intervallo per un valore che corrisponde a un predicato, in questo caso un funtore non_alpha che restituisce se il suo argomento è un carattere non alfabetico. Se find_if(name.begin(), name.end(), ...) restituisce name.end(), non è stata trovata alcuna corrispondenza.

Ma c'è di più!

Per fare questo come una battuta, è possibile utilizzare gli adattatori dalla <functional> intestazione:

#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(); 

Il std::not1 produce un oggetto funzione che restituisce l'inverso logico del suo ingresso; fornendo un puntatore a una funzione con std::ptr_fun(...), possiamo dire a std::not1 di produrre l'inverso logico di std::isalpha. Il cast (int(*)(int)) è lì per selezionare il sovraccarico di std::isalpha che accetta uno int (trattato come un carattere) e restituisce un int (considerato come un booleano).

Oppure, se è possibile utilizzare un compilatore C++ 11, con un lambda pulisce questo un sacco:

#include <cctype> 

bool contains_non_alpha 
    = std::find_if(name.begin(), name.end(), 
        [](char c) { return !std::isalpha(c); }) != name.end(); 

[](char c) -> bool { ... } indica una funzione che accetta un carattere e restituisce un bool. Nel nostro caso possiamo omettere il tipo di ritorno -> bool perché il corpo della funzione è costituito solo da un'istruzione return. Funziona esattamente come gli esempi precedenti, con la differenza che l'oggetto funzione può essere specificato in modo molto più succinto.

e (quasi) finalmente ...

In C++ 11 si può anche usare un'espressione regolare per eseguire il match:

#include <regex> 

bool contains_non_alpha 
    = !std::regex_match(name, std::regex("^[A-Za-z]+$")); 

Ma naturalmente ...

Nessuna di queste soluzioni affronta il problema della localizzazione o della codifica dei caratteri! Per una versione locale-indipendente isalpha(), avresti bisogno di usare il C++ intestazione <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); 
} 

Idealmente vorremmo usare char32_t, ma ctype non sembra essere in grado di classificare, quindi stiamo bloccato con char. Fortunatamente per noi possiamo ballare interamente sulla questione del locale, perché probabilmente ti interessano solo le lettere inglesi. C'è una comoda libreria di sola intestazione chiamata UTF8-CPP che ci permetterà di fare ciò che dobbiamo fare in un modo più sicuro per la codifica. In primo luogo definiamo la nostra versione di isalpha() che utilizza UTF-32 punti di codice:

bool isalpha(uint32_t c) { 
    return (c >= 0x0041 && c <= 0x005A) 
     || (c >= 0x0061 && c <= 0x007A); 
} 

Poi possiamo usare l'adattatore utf8::iterator di adattare il basic_string::iterator da ottetti in UTF-32 punti di codice:

#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(); 

Per un po 'meglio le prestazioni a scapito della sicurezza, è possibile utilizzare 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(); 

Questo falliranno su alcuni inpu non valida t.

L'utilizzo di UTF8-CPP in questo modo presuppone che la codifica dell'host sia UTF-8 o una codifica compatibile come ASCII. In teoria questa è ancora una soluzione imperfetta, ma in pratica funzionerà sulla stragrande maggioranza delle piattaforme.

Spero che questa risposta sia finalmente completa!

+0

+1 Non sono sicuro che questo approccio funzionerebbe in un ambiente i18n con unicode non inglese in wchars, ecc., Ma ottima risposta. :) –

+1

nome.find_first_not_of restituisce posizione o npos (-1). Questo significa che il risultato, una volta lanciato in bool, sarà sempre vero. È necessario testare contro npos perché ciò abbia senso. – flumpb

+0

@kisplit: Grazie per averlo capito. Solo una svista da parte mia. –

2

Vorrei suggerire indagare biblioteca ctype: http://www.cplusplus.com/reference/std/locale/ctype/

Ad esempio, la funzione is (vedi ctype.is) è un modo per verificare immobili in lettere in maniera sensibile locale:

#include <locale> 
using namespace std; 
bool is_alpha(char c) { 
    locale loc; 
    bool upper = use_facet< ctype<char> >(loc).is(ctype<char>::alpha, quote[0]); 
    return upper; 
} 
2
for (string::iterator it=name.begin(); it!=name.end(); ++it) 
    { 
    if ((*it) < 0x61 || (*it) > 0x71) 
     // string contains characters other than a-z 
    } 
+0

il numero esadecimale è sbagliato. si prega di aggiornarlo con i codici esadecimale corretti (consultare asciitable.com). Inoltre, puoi anche scegliere "A" - "Z". – CyprUS

+1

Evita numeri magici e usa ''A'' e'' Z'', ma nota che questa condizione è falsa per sistema come [EBCDIC] (https://en.wikipedia.org/wiki/EBCDIC). – Jarod42

5

Se si utilizza Boost, è possibile utilizzare il predicato boost::algorithm::is_alpha per eseguire questo controllo. Ecco come usarlo:

const char* text = "hello world"; 
bool isAlpha = all(text1, is_alpha()); 

Aggiornamento: Come afferma di documentazione, "tutti() controlla tutti gli elementi di un contenitore per soddisfare una condizione specificata da un predicato". La chiamata a tutti() è necessaria qui, poiché is_alpha() opera effettivamente sui caratteri.

Spero, ho aiutato.

+0

Probabilmente intendevi 'const char * test' – curiousguy

+0

@curiousguy: grazie. indirizzata. – Lev

+1

Si potrebbe voler mostrare ciò che si chiama 'tutto' e' is_alpha' da soli non funzionerà a meno che non si abbia il corretto 'use namespace' che in genere non è raccomandato. Inoltre, che cos'è 'text1'? –

Problemi correlati