たとえば、ユーザーに電話番号を入力してもらいます。
cout << "Enter phone number: ";
INPUT: (555) 555-5555
cin >> phone;
文字列から「(」、「)」、「-」の文字を削除したい。文字列の削除、検索、および置換関数を見てきましたが、位置に基づいて動作することしかわかりません。
文字(「」など)を渡すために使用できる文字列関数があり、文字列内のすべてのインスタンスを削除しますか?
string str("(555) 555-5555");
char chars[] = "()-";
for (unsigned int i = 0; i < strlen(chars); ++i)
{
// you need include <algorithm> to use general algorithms like std::remove()
str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());
}
// output: 555 5555555
cout << str << endl;
functionとして使用するには:
void removeCharsFromString( string &str, char* charsToRemove ) {
for ( unsigned int i = 0; i < strlen(charsToRemove); ++i ) {
str.erase( remove(str.begin(), str.end(), charsToRemove[i]), str.end() );
}
}
//example of usage:
removeCharsFromString( str, "()-" );
文字列から「(」、「)」、「-」の文字を削除したい。
std::remove_if()
アルゴリズムを使用して、指定した文字のみを削除できます。
#include <iostream>
#include <algorithm>
#include <string>
bool IsParenthesesOrDash(char c)
{
switch(c)
{
case '(':
case ')':
case '-':
return true;
default:
return false;
}
}
int main()
{
std::string str("(555) 555-5555");
str.erase(std::remove_if(str.begin(), str.end(), &IsParenthesesOrDash), str.end());
std::cout << str << std::endl; // Expected output: 555 5555555
}
std::remove_if()
アルゴリズムには、述部と呼ばれるものが必要です。これは、上記のスニペットのような関数ポインターになります。
関数オブジェクト(関数呼び出し()
演算子をオーバーロードするオブジェクト)を渡すこともできます。これにより、さらに一般的なソリューションを作成できます。
#include <iostream>
#include <algorithm>
#include <string>
class IsChars
{
public:
IsChars(const char* charsToRemove) : chars(charsToRemove) {};
bool operator()(char c)
{
for(const char* testChar = chars; *testChar != 0; ++testChar)
{
if(*testChar == c) { return true; }
}
return false;
}
private:
const char* chars;
};
int main()
{
std::string str("(555) 555-5555");
str.erase(std::remove_if(str.begin(), str.end(), IsChars("()- ")), str.end());
std::cout << str << std::endl; // Expected output: 5555555555
}
"()- "
文字列を使用して、削除する文字を指定できます。上記の例では、スペースを追加して、スペースと括弧およびダッシュを削除しました。
remove_if()はすでに言及されています。ただし、C++ 0xでは、代わりにラムダを使用して述語を指定できます。
以下は、フィルタリングを実行する3つの異なる方法を使用した例です。関数の「コピー」バージョンは、constで作業している場合、または元のコードを変更したくない場合にも含まれています。
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;
string& remove_chars(string& s, const string& chars) {
s.erase(remove_if(s.begin(), s.end(), [&chars](const char& c) {
return chars.find(c) != string::npos;
}), s.end());
return s;
}
string remove_chars_copy(string s, const string& chars) {
return remove_chars(s, chars);
}
string& remove_nondigit(string& s) {
s.erase(remove_if(s.begin(), s.end(), [](const char& c) {
return !isdigit(c);
}), s.end());
return s;
}
string remove_nondigit_copy(string s) {
return remove_nondigit(s);
}
string& remove_chars_if_not(string& s, const string& allowed) {
s.erase(remove_if(s.begin(), s.end(), [&allowed](const char& c) {
return allowed.find(c) == string::npos;
}), s.end());
return s;
}
string remove_chars_if_not_copy(string s, const string& allowed) {
return remove_chars_if_not(s, allowed);
}
int main() {
const string test1("(555) 555-5555");
string test2(test1);
string test3(test1);
string test4(test1);
cout << remove_chars_copy(test1, "()- ") << endl;
cout << remove_chars(test2, "()- ") << endl;
cout << remove_nondigit_copy(test1) << endl;
cout << remove_nondigit(test3) << endl;
cout << remove_chars_if_not_copy(test1, "0123456789") << endl;
cout << remove_chars_if_not(test4, "0123456789") << endl;
}
ここに興味がある人のための別のソリューションがあります。 C++ 11の新しいFor範囲を使用します
string str("(555) 555-5555");
string str2="";
for (const auto c: str){
if(!ispunct(c)){
str2.Push_back(c);
}
}
str = str2;
//output: 555 5555555
cout<<str<<endl;
Std :: stringにはそのようなメンバーは存在しないのではないかと心配していますが、そのような関数を簡単にプログラムできます。それは最速のソリューションではないかもしれませんが、これで十分でしょう:
std::string RemoveChars(const std::string& source, const std::string& chars) {
std::string result="";
for (unsigned int i=0; i<source.length(); i++) {
bool foundany=false;
for (unsigned int j=0; j<chars.length() && !foundany; j++) {
foundany=(source[i]==chars[j]);
}
if (!foundany) {
result+=source[i];
}
}
return result;
}
編集:以下の答えを読んで、私はそれが数字を検出するだけでなく、より一般的であることを理解しました。上記のソリューションでは、2番目の引数文字列で渡されるすべての文字が省略されます。例えば:
std::string result=RemoveChars("(999)99-8765-43.87", "()-");
結果として
99999876543.87
boost::is_any_of
別の指定された文字列に現れる1つの文字列からすべての文字を削除します。
#include <cassert>
#include <boost/range/algorithm/remove_if.hpp>
#include <boost/algorithm/string/classification.hpp>
int main() {
std::string str = "a_bc0_d";
str.erase(boost::remove_if(str, boost::is_any_of("_0")), str.end());
assert((str == "abcd"));
}
Ubuntu 16.04、Boost 1.58でテスト済み。
using namespace std;
// c++03
string s = "(555) 555-5555";
s.erase(remove_if(s.begin(), s.end(), not1(ptr_fun(::isdigit))), s.end());
// c++11
s.erase(remove_if(s.begin(), s.end(), ptr_fun(::ispunct)), s.end());
注:単純なptr_fun<int, int>
ではなく、ptr_fun
と書く必要がある可能性があります
はい、isdigit()関数を使用して数字を確認できます:)
どうぞ:
#include <iostream>
#include <cctype>
#include <string.h>
using namespace std;
int main(){
char *str = "(555) 555-5555";
int len = strlen(str);
for (int i=0; i<len; i++){
if (isdigit(*(str+i))){
cout << *(str+i);
}
}
cout << endl;
return 0;
}
それが役に立てば幸い :)
さらに別の選択肢があります:
template<typename T>
void Remove( std::basic_string<T> & Str, const T * CharsToRemove )
{
std::basic_string<T>::size_type pos = 0;
while (( pos = Str.find_first_of( CharsToRemove, pos )) != std::basic_string<T>::npos )
{
Str.erase( pos, 1 );
}
}
std::string a ("(555) 555-5555");
Remove( a, "()-");
Std :: stringおよびstd :: wstringで動作します
可変長テンプレートをサポートするコンパイラにアクセスできる場合、これを使用できます。
#include <iostream>
#include <string>
#include <algorithm>
template<char ... CharacterList>
inline bool check_characters(char c) {
char match_characters[sizeof...(CharacterList)] = { CharacterList... };
for(int i = 0; i < sizeof...(CharacterList); ++i) {
if(c == match_characters[i]) {
return true;
}
}
return false;
}
template<char ... CharacterList>
inline void strip_characters(std::string & str) {
str.erase(std::remove_if(str.begin(), str.end(), &check_characters<CharacterList...>), str.end());
}
int main()
{
std::string str("(555) 555-5555");
strip_characters< '(',')','-' >(str);
std::cout << str << std::endl;
}
私は新しいですが、上記の答えのいくつかはめちゃくちゃ複雑ですので、ここに代替案があります。
注:0〜9が連続している限り(標準に従っている必要があります)、数字と「」以外のすべての文字を除外する必要があります。 0-9は連続している必要があり、charは実際にはintであることがわかっているので、以下を行うことができます。
編集:ポスターにもスペースが必要なことに気づかなかったので、変更しました...
#include <cstdio>
#include <cstring>
void numfilter(char * buff, const char * string)
{
do
{ // According to standard, 0-9 should be contiguous in system int value.
if ( (*string >= '0' && *string <= '9') || *string == ' ')
*buff++ = *string;
} while ( *++string );
*buff++ = '\0'; // Null terminate
}
int main()
{
const char *string = "(555) 555-5555";
char buff[ strlen(string) + 1 ];
numfilter(buff, string);
printf("%s\n", buff);
return 0;
}
以下は、提供された文字をフィルタリングするためのものです。
#include <cstdio>
#include <cstring>
void cfilter(char * buff, const char * string, const char * toks)
{
const char * tmp; // So we can keep toks pointer addr.
do
{
tmp = toks;
*buff++ = *string; // Assume it's correct and place it.
do // I can't think of a faster way.
{
if (*string == *tmp)
{
buff--; // Not correct, pull back and move on.
break;
}
}while (*++tmp);
}while (*++string);
*buff++ = '\0'; // Null terminate
}
int main()
{
char * string = "(555) 555-5555";
char * toks = "()-";
char buff[ strlen(string) + 1 ];
cfilter(buff, string, toks);
printf("%s\n", buff);
return 0;
}
より簡潔で読みやすいラムダコーディングスタイルを好む人のために...
この例では、ワイド文字列からすべての非英数字および空白文字を削除します。他の ctype.h ヘルパー関数と組み合わせて、複雑に見える文字ベースのテストを削除できます。
(これらの関数がCJK言語をどのように処理するかはわかりませんので、そっと歩いてください。)
// Boring C loops: 'for(int i=0;i<str.size();i++)'
// Boring C++ eqivalent: 'for(iterator iter=c.begin; iter != c.end; ++iter)'
ノイズの多いC/C++ for/iteratorループよりも理解しやすいかどうかを確認してください。
TSTRING label = _T("1. Replen & Move RPMV");
TSTRING newLabel = label;
set<TCHAR> badChars; // Use ispunct, isalpha, isdigit, et.al. (lambda version, with capture list parameter(s) example; handiest thing since sliced bread)
for_each(label.begin(), label.end(), [&badChars](TCHAR n){
if (!isalpha(n) && !isdigit(n))
badChars.insert(n);
});
for_each(badChars.begin(), badChars.end(), [&newLabel](TCHAR n){
newLabel.erase(std::remove(newLabel.begin(), newLabel.end(), n), newLabel.end());
});
このコードの実行後のnewLabelの結果:「1ReplenMoveRPMV」
Lambda0の 'if'ロジック(最初のfor_each)を単一のlambda1(2番目for_each)、どの文字が「badChars」であるかを既に確立している場合。
std :: wstringおよびwchar_tの使用(Unicodeヘッダー):
//#include <tchar.h>
std::wstring phone(L"(555) 555-5555");
...次は静的な範囲初期化子です;これとまったく同じ方法でbadChars2をセットアップする必要はありません。それはやり過ぎです。何よりもアカデミック:
const wchar_t *tmp = L"()-";
const std::set<wchar_t> badChars2(tmp,tmp + sizeof(tmp)-1);
シンプルで簡潔なラムダ:
phoneからすべての不良文字を削除します
for_each(badChars2.begin(), badChars2.end(), [&phone](wchar_t n){
phone.erase(std::remove(phone.begin(), phone.end(), n), phone.end());
});
wcout << phone << endl;
出力:「555 5555555」