如何使用 C++/Boost 过滤字符串中的字符
Posted
技术标签:
【中文标题】如何使用 C++/Boost 过滤字符串中的字符【英文标题】:How to filter characters from a string with C++/Boost 【发布时间】:2010-07-08 17:29:44 【问题描述】:这似乎是一个非常基本的问题,所以如果它已经在某个地方得到回答,我深表歉意(我的搜索没有找到任何东西)。
我只想过滤一个字符串对象,使其只包含字母数字和空格字符。
这是我尝试过的:
#include "boost/algorithm/string/erase.hpp"
#include "boost/algorithm/string/classification.hpp"
std::wstring oldStr = "Bla=bla =&*\nSampleSampleSample ";
std::wstring newStr = boost::erase_all_copy(oldStr, !(boost::is_alnum() ||
boost::is_space()));
但是编译器对此一点也不满意——看来我只能在erase_all_copy
的第二个参数中放入一个字符串,而不是is_alnum()
的东西。
我在这里缺少一些明显的解决方案吗?
【问题讨论】:
【参考方案1】:使用 std 算法和 Boost.Bind:
std::wstring s = ...
std::wstring new_s;
std::locale loc;
std::remove_copy_if(s.begin(), s.end(), std::back_inserter(new_s),
!(boost::bind(&std::isalnum<wchar_t>, _1, loc)||
boost::bind(&std::isspace<wchar_t>, _1, loc)
));
【讨论】:
成功了,谢谢!在这一点上,这一切对我来说都像是黑魔法,但它会给我一个更好地理解迭代器和 C++ 方式的地方。 @jjiffer: remove_copy_if 接受一个输入范围(“s.begin(), s.end()”部分)和一个输出迭代器,它将提取的字符写入其中(“back_inserter(new_s )“ 部分)。第四个参数是一个函数对象,它接受一个元素作为输入(在本例中为 wchar_t)并返回 bool。如果此函数返回 true,则跳过该元素。 (待续......) 这个函数对象是在这里用 boost::bind 创建的。 "bind(&isalnum, _1, loc)" 返回一个函数对象,该对象存储指向 isalnum 函数的指针和 "loc" 的副本。该函数对象在使用一个参数调用时将依次调用 isalnum(the_argument, loc) 并返回其结果。最后,运算符重载魔法允许我们将使用绑定创建的两个函数对象与 OR 运算符组合,并使用 NOT 运算符对其结果求反。 啊,我明白了。我不知道 C++ 有任何类似绑定的东西。谢谢解释!【参考方案2】:我使用 boost 已经有好几年了,但也许您可以使用 erase_all_regex_copy() 而不是 erase_all_copy()?这可能会影响性能,但除了迭代每个元素并手动检查之外,它可能是您唯一的选择。如果您不熟悉正则表达式,在这种情况下您将使用的表达式类似于“[^a-zA-Z0-9 ]+”。
为了完整起见,一些示例代码:
#include "boost/regex.hpp"
#include "boost/algorithm/string/regex.hpp"
std::wstring oldStr = "Bla=bla =&*\nSampleSampleSample ";
std::wstring newStr = boost::erase_all_regex_copy(oldStr, boost::regex("[^a-zA-Z0-9 ]+"));
【讨论】:
我收到有关 char_t 和 wchar_t 转换的错误。也许这个正则表达式隐含地假设 char_t 而不是 wchar_t?我在正则表达式字符串前面放了一个 L,但它也不喜欢这样。 long long 错误消息的开头: C:\boost_1_40_0\boost/regex/v4/perl_matcher_common.hpp(802) : warning C4244: 'argument' : conversion from 'const wchar_t' to 'char', possible loss of data 试试把 boost::regex("etc.") 改成 boost::regex对于那些不太聪明的人,这里是基于@Éric Malenfant 回答的 ANSI 和 UNICODE 函数:
std::string CleanString(const std::string& Input)
std::string clean_string;
std::locale loc;
try
std::remove_copy_if(Input.begin(), Input.end(), std::back_inserter(clean_string),
!(boost::bind(&std::isalnum<unsigned char>, _1, loc) || boost::bind(&std::isspace<unsigned char>, _1, loc)
));
catch (const std::bad_alloc& e)
std::cout << "Allocation failed: " << e.what() << '\n';
return clean_string;
std::wstring CleanString(const std::wstring& Input)
std::wstring clean_string;
std::locale loc;
try
std::remove_copy_if(Input.begin(), Input.end(), std::back_inserter(clean_string),
!(boost::bind(&std::isalnum<wchar_t>, _1, loc) ||
boost::bind(&std::isspace<wchar_t>, _1, loc)
));
catch (const std::bad_alloc& e)
std::cout << "Allocation failed: " << e.what() << '\n';
return clean_string;
在线演示:https://wandbox.org/permlink/MFTwXV4ZCi9nsdlC
Linux 的完整测试代码:
#include <iostream>
#include <algorithm>
#include <cctype>
#include <boost/bind.hpp>
// Note on Linux we use char and not unsigned char!
std::string CleanString(const std::string& Input)
std::string clean_string;
std::locale loc;
try
std::remove_copy_if(Input.begin(), Input.end(), std::back_inserter(clean_string),
!(boost::bind(&std::isalnum<char>, _1, loc) || boost::bind(&std::isspace<char>, _1, loc)
));
catch (const std::bad_alloc& e)
std::cout << "Allocation failed: " << e.what() << '\n';
catch (...)
return clean_string;
std::wstring CleanString(const std::wstring& Input)
std::wstring clean_string;
std::locale loc;
try
std::remove_copy_if(Input.begin(), Input.end(), std::back_inserter(clean_string),
!(boost::bind(&std::isalnum<wchar_t>, _1, loc) ||
boost::bind(&std::isspace<wchar_t>, _1, loc)
));
catch (const std::bad_alloc& e)
std::cout << "Allocation failed: " << e.what() << '\n';
catch (...)
return clean_string;
int main()
std::string test_1 = "Bla=bla =&*\n Sample Sample Sample !$%^&*@~";
std::string new_test_1 = CleanString(test_1);
if (!new_test_1.empty())
std::cout << "ANSI: " << new_test_1 << std::endl;
std::wstring test_uc_1 = L"!$%^&*@~ test &*";
std::wstring new_test_uc_1 = CleanString(test_uc_1);
if (!new_test_uc_1.empty())
std::wcout << L"UNICODE: " << new_test_uc_1 << std::endl;
return 0;
感谢 Éric Malenfant。
【讨论】:
以上是关于如何使用 C++/Boost 过滤字符串中的字符的主要内容,如果未能解决你的问题,请参考以下文章