2011-09-30 75 views
14

我怎麼能測試只針對像字母AZ有效字符的字符串...如何測試僅

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

如果這是作業...它應該被標記爲這樣。 –

+0

你的問題是什麼?你的代碼是錯誤的還是缺少的?在這種情況下,什麼? –

+3

'* it'。順便說一句,也可以嘗試與dvorak佈局。 –

回答

3

STL的方式爲字母的字符串:

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

如果我想將空格作爲測試參數的一部分,那麼該怎麼辦?你會怎麼做? – miatech

+0

替換'if(stringIsCorrect &&!((ch <='z'&&> ='a')||(ch <='Z'&& ch> ='A')))'with'if(stringIsCorrect && !(ch <='z'&& ch> ='a')||(ch <='Z'&& ch> ='A')||(ch =='')))' – GreenScape

+1

請注意,編碼因爲[EBCDIC](https://en.wikipedia.org/wiki/EBCDIC)在「a」和「z」之間的字符不是字母。 – Jarod42

43

首先,使用std::cin >> name會如果用戶輸入John Smith,則會失敗,因爲>>會將輸入分割爲空白字符。您應該使用std::getline()得到名稱:

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

在這裏,我們去...

有許多的方法可以檢查字符串只包含字母字符。最簡單的是可能s.find_first_not_of(t),它返回第一個字符的s指數,是不是在t

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

這迅速變得麻煩,但是。要也匹配大寫字母字符,您必須爲該字符串添加26個字符!相反,你可能想從<cctype>使用find_if組合從<algorithm>頭和std::isalpha

#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搜索了一系列針對匹配的謂語,在這種情況下,值的仿函數non_alpha返回無論其參數是非字母字符。如果find_if(name.begin(), name.end(), ...)返回name.end(),則找不到匹配。

但還有更多!

爲此作爲一襯墊,可以使用適配器從<functional>頭:

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

std::not1產生一個函數對象返回其輸入的邏輯逆;通過給函數std::ptr_fun(...)提供一個指針,我們可以告訴std::not1產生std::isalpha的邏輯逆。演員(int(*)(int))是在那裏選擇std::isalpha的過載,其中需要int(視爲字符)並返回int(視爲布爾值)。

或者,如果你可以使用C++編譯器11,使用Lambda清除該漲了不少:

#include <cctype> 

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

[](char c) -> bool { ... }表示接受一個字符,返回bool功能。在我們的例子中,我們可以省略-> bool返回類型,因爲函數體只包含return語句。除了可以更簡潔地指定函數對象之外,其工作原理與前面的示例相同。

和(幾乎)終於...

在C++ 11你也可以使用正則表達式來進行匹配:

#include <regex> 

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

但當然...

但是沒有一個方案解決語言環境或字符編碼的問題!對於isalpha()區域設置獨立的版本,你需要使用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); 
} 

理想情況下,我們會使用char32_t,但ctype似乎不能夠對其進行分類,所以我們堅持char。對我們來說幸運的是,我們完全可以圍繞語言環境跳舞,因爲您可能只對英文字母感興趣。有一個名爲UTF8-CPP的方便標題庫,可以讓我們以更安全的編碼方式來做我們需要做的事情。首先我們定義的isalpha()版本,使用UTF-32代碼點:

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

然後我們可以使用utf8::iterator適配器爲basic_string::iterator從八位字節改編成UTF-32代碼點:

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

對於在稍微安全的成本更好的性能,可以使用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(); 

這將失敗的一些無效inpu噸。

以這種方式使用UTF8-CPP假定主機編碼爲UTF-8或兼容編碼,如ASCII。從理論上講,這仍然是一個不完美的解決方案,但實際上它將在絕大多數平臺上運行。

我希望這個答案終於完成了!

+0

+1我不確定這種方法是否可以在國際環境中使用非英文unicode等,但反應很好。 :) –

+1

name.find_first_not_of返回位置或npos(-1)。這意味着,結果,當布爾bool永遠是真實的。您需要針對npos進行測試才能發揮作用。 – flumpb

+0

@kisplit:謝謝你的發現。只是我的一個疏忽。 –

2

我建議調查CTYPE的庫: http://www.cplusplus.com/reference/std/locale/ctype/

例如,函數is(見ctype.is)是一種方法來檢查區域設置敏感的方式對信件性質:

#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

十六進制數是錯誤的。請用正確的HEX代碼更新它(請參閱asciitable.com)。另外,你也可以選擇'A' - 'Z'。 – CyprUS

+1

避免神奇數字使用「A」和「Z」,但請注意,這種情況對於系統是錯誤的[EBCDIC](https://en.wikipedia.org/wiki/EBCDIC)。 – Jarod42

5

如果使用Boost,則可以使用boost::algorithm::is_alpha謂詞執行此檢查。下面是如何使用它:

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

更新: 作爲文檔狀態,「所有()檢查一個容器中的所有元素以滿足由謂詞指定的條件」。這裏需要調用all(),因爲is_alpha()實際上是對字符進行操作的。

希望,我幫了忙。

+0

你可能的意思是'const char * test' – curiousguy

+0

@curiousguy:謝謝。解決。 – Lev

+1

你可能想要顯示你自己調用完全限定的'all'和'is_alpha'自己不會工作,除非你有正確的'use namespace',這通常是不推薦的。另外,'text1'是什麼? –