文字列に特殊文字が含まれているかどうかを確認するためのより良い方法があるかどうかを調べようとしています。私の場合、英数字と「_」以外は特殊文字と見なされます。現在、std :: string = "!@#$%^&"などの特殊文字を含む文字列があります。次に、std :: find_first_of()アルゴリズムを使用して、文字列に特殊文字が存在するかどうかを確認します。
ホワイトリストに基づいてそれを行う方法を考えていました。文字列に小文字/大文字、数字、アンダースコアを指定したい(リストしたくない。[a-zA-Z0-9_]のようなASCII範囲を指定する方法はありますか? )。どうすればこれを達成できますか?次に、std :: find_first_not_of()を使用する予定です。このようにして、私が実際に欲しいものに言及し、反対をチェックすることができます。
試してみてください:
std::string x(/*Load*/);
if (x.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_") != std::string::npos)
{
std::cerr << "Error\n";
}
または、正規表現をブーストしてみてください。
// Note: \w matches any Word character `alphanumeric plus "_"`
boost::regex test("\w+", re,boost::regex::Perl);
if (!boost::regex_match(x.begin(), x.end(), test)
{
std::cerr << "Error\n";
}
// The equivalent to \w should be:
boost::regex test("[A-Za-z0-9_]+", re,boost::regex::Perl);
標準のCまたはC++を使用して文字範囲を使用する方法はありません。すべての文字をリストする必要があります。 C文字列の場合、 strspn(3)
および strcspn(3)
を使用して、またはのメンバーである文字列の最初の文字を検索できます。特定の文字セットのメンバーではありません。例えば:
_// Test if the given string has anything not in A-Za-z0-9_
bool HasSpecialCharacters(const char *str)
{
return str[strspn(str, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_")] != 0;
}
_
C++文字列の場合、_find_first_of
_および_find_first_not_of
_メンバー関数を同等に使用できます。
もう1つのオプションは、_<ctype.h>
_の isalnum(3)
および関連関数 を使用して、特定の文字が英数字かどうかをテストすることです。これらの関数はロケールに依存しているので、他のロケールでは動作が変わる可能性がある(そして変わる)ことに注意してください。その動作を望まない場合は、それらを使用しないでください。それらを使用することを選択した場合は、「アルファベット、数値、またはアンダースコア」をテストする関数がないため、アンダースコアも個別にテストする必要があります。また、文字列を検索するために独自のループをコーディングする必要があります(または、適切な関数オブジェクトで_std::find
_を使用します)。
最初に考慮する必要があるのは、「これはASCIIのみ」ですか?「はい」と答えた場合は、ASCIIのみ。私は現在、最初からユニコードをサポートすることを考えていなかったため、海外市場に参入するのに本当に頭痛の種を抱えている会社で働いています。
そうは言っても、ASCIIを使用すると、アルファ以外の数値を簡単に確認できます。asciiチャートを見てください。
http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
std::string
をコレクションとして扱い、アルゴリズムを使用して、少し違った方法で作業を行うと思います。 C++ 0xラムダを使用すると、次のようになります。
bool has_special_char(std::string const &str) {
return std::find_if(str.begin(), str.end(),
[](char ch) { return !(isalnum(ch) || ch == '_'); }) != str.end();
}
少なくともchar
(wchar_t
ではない)を扱っている場合、isalnum
は通常、テーブルルックアップを使用するため、通常は(かなり)高速になります。 find_first_of
に基づくもの(通常は代わりに線形検索を使用します)。 IOW、これはO(N)(N = str.size())です。ここで、find_first_of
に基づくものはO(N * M)、(N = str。 size()、M = pattern.size())。
純粋なCで仕事をしたい場合は、理論的には移植性がないが、本質的にすべての最近の/人気のあるコンパイラでサポートされているスキャンセット変換でscanf
を使用できます。
char junk;
if (sscanf(str, "%*[A-Za-z0-9_]%c", &junk))
/* it has at least one "special" character
else
/* no special characters */
ここでの基本的な考え方は非常に単純です。スキャンセットは、連続するすべての非特殊文字をスキップし(ただし、*
のため、結果を何にも割り当てません)、もう1文字を読み取ろうとします。それが成功した場合は、notスキップされた文字が少なくとも1つあったことを意味するため、少なくとも1つの特殊文字が必要です。失敗した場合は、スキャンセット変換が文字列全体と一致したことを意味するため、すべての文字が「非特殊」でした。
公式には、C標準では、このようなスキャンセット変換に範囲を入れようとすると、移植性がないとされています(スキャンセットの最初または最後以外の場所にある「-」は、実装で定義された動作を提供します)。これに失敗するコンパイラー(Borland製)もいくつかあります。それらは、A-Z
を「A」、「-」、「Z」の3つの文字に正確に一致するものとして扱います。現在のほとんどのコンパイラ(より正確には、標準ライブラリの実装)は、これが想定するアプローチを採用しています。「A-Z」は任意の大文字に一致します。
関数(マクロ)はロケール設定の対象となりますが、isalnum()
および<ctype.h>
または<cctype>
からの関連を調査する必要があります。
使用する
s.erase(std::remove_if(s.begin(), s.end(), my_predicate), s.end());
bool my_predicate(char c)
{
return !(isalpha(c) || c=='_');
}
クリーンな文字列s
を取得します。
消去すると、すべての特殊文字が削除され、my_predicate
関数を使用して高度にカスタマイズできます。
ここでは、組み込みのC機能を使用します。文字列内の各文字を繰り返し処理し、それが__
_であるかどうか、またはisalpha(ch)
がtrueであるかどうかを確認します。もしそうならそれは有効です、そうでなければそれは特殊文字です。
これが必要であるが、完全に行き過ぎて正規表現を使用したくない場合、およびテストがASCII chars -find_first_not_of
の文字列を生成する関数を作成するだけです。 ..
#include <iostream>
#include <string>
std::string expand(const char* p)
{
std::string result;
while (*p)
if (p[1] == '-' && p[2])
{
for (int c = p[0]; c <= p[2]; ++c)
result += (char)c;
p += 3;
}
else
result += *p++;
return result;
}
int main()
{
std::cout << expand("A-Za-z0-9_") << '\n';
}