BOOST库 之 tokenizer 字符串的分解

一、包含
include <boost/tokenizer.hpp>
using namespace boost;

二、摘要

tokenizer库是一个专门用于分词(token)的字符串处理库,可以使用简单易用的方法把一个字符串分解成若干个单词。


三、类型说明

template< typename TokenizerFunc = char_delimiters_separator<char>,
			typename Iterator = std::string::const_iterator,
			typename Type = std::string >
class tokenizer
{
	tokenizer( Iterator first, Iterator last, const TokenizerFunc & f );
	tokenizer( const Container & c, const TokenizerFunc & f );


	void assign( Iterator first, Iterator last );
	void assign( const Container& c );
	void assign( const Container& c, const TokenizerFunc& f );


	iterator begin() const;
	iterator end() const;
}
tokenizer接受三个模板类型参数,分别是:

 TokenizerFunc  : tokenizer库专门的分词函数对象,默认是使用空格和标点分词;
 Iterator       : 字符序列的迭代器类型;
 Type           : 保存分词结果的类型;

这三个模板类型都提供了默认值,但通常只有前两个模板参数可以变化,第三个类型一般只能选择std::string或者std::wstring,这也是它位于模板参数列表最后的原因.

tokenizer的构造函数接受要进行分词的字符串,可以以迭代器的区间形式给出,也可以使一个有begin()和end()成员函数的容器.

四、用法:
tokenizer的用法很像 string_algo 的分割迭代器,但要简单一些。可以像使用一个容器那样使用它,
向tokenizer传入一个欲分词的字符串构造,然后用begin()获得迭代器反复迭代,就可以轻松完成分词功能.

{
	std::string str( "Link raise the master-sword." );

	boost::tokenizer<> tok( str ); //使用缺省目标参数创建分词对象(默认是使用空格和标点分词);

	//可以像遍历一个容器一样使用for循环获得分词结果;
	for ( BOOST_AUTO( pos, tok.begin() ); pos != tok.end(); ++pos )
	{
		cout << "[" << *pos << "]";
	}

	//运行结果;
	//[Link][raise][the][master][sword]

	//【注】
	//tokenizer默认把所有的空格和标点符号作为分隔符,因此分割出的只是单词。
}

五、分词函数对象
tokenizer的真正威力在于第一个模板类型参数TokenizerFunc。TokenizerFunc是一个函数对象,它决定如何
进行分词处理。TokenizerFunc同时也是一个规范,只要具有合适的operator()和reset()语言的函数对象都可
用于tokenizer分词。

    四个分词对象:
 char_delimiters_separator  : 使用标点符号分词,是tokenizer默认使用的分词函数对象。但已废弃,尽量不使用它.
 char_sparator              : 它支持一个字符集合作为分隔符,默认的行为与char_delimiters_sparator类似.
 escaped_list_separator     : 用于CSV格式(逗号分隔)的分词.
 offset_separator           : 使用偏移量来分词,在分解平文件格式的字符串时很有用.

template<typename T>
void print( T & tok )
{
	for ( BOOST_AUTO(pos, tok.begin()); pos != tok.end(); ++pos )
	{
		cout << "[" << *pos << "]";
	}
	cout << endl;
}

//①char_sparator
//构造声明
char_separator( const char * droppen_delims,
				const char * kept_delims = 0,
				empty_token_policy empty_tokens = drop_empty_tokens );

//参数说明:
//第一个参数 droppen_delims 是分隔符集合,这个集合中的字符不会作为分词结果出现;
//第二个参数 kept_delims 也是分隔符集合,但其中的字符会保留在分区结果中;
//第三个参数 empty_tokens 类似split算法的eCompress参数,处理两个连续出现的分隔符。
	//如为 keep_empty_tokens 则表示连续出现的分隔符标识了一个空字符串,相当于split
	//算法的token_compress_off值;如为drop_empty_tokens,则空白单词不会作为分词的结果.

//如果使用默认的构造函数,不传入任何参数,则其行为等同于 char_separator( "", 标点符号字符, drop_empty_tokens )
//以空格和标点符号分词,保留标点符号,不输出空白单词.

char * str = "Link ;; <master-sword> zelda";

boost::char_separator<char> sep; //一个char_separator对象;
boost::tokenizer<boost::char_separator<char>, char*> tok( str, str + strlen(str), sep ); //传入char_separator构造分词对象

print( tok ); //分词并输出

//重新分词
tok.assign( str, str + strlen(str), boost::char_separator<char>(" ;-", "<>") );
print( tok );

	//重新分词
tok.assign( str, str + strlen(str), boost::char_separator<char>(" ;-<>", "", keep_empty_tokens) );
print( tok );

//对tokenizer的目标参数做了改变,第二个参数改为 char*,这使得tokenizer可以分析C风格的字符串数组。同时构造函数也必须变为
//传入字符串的首末位置,不能仅传递一个字符串首地址,因为字符串数组不符合容器的概念.

//第一次分词我们使用 char_separator的缺省构造,以空格和标点分词,保留标点作为单词的一部分,并抛弃空白单词;
//第二次分词我们使用" ;-"和"<>"共5个字符分词,保留<>作为单词的一部分,同样抛弃空白单词;
//最后一次分词我们同样使用" ;-<>"分词,但它们都不作为单词的一部分,并且我们保留空白单词.

//程序运行结果:
//[Link][;][;][<][master][-][sword][>][zelda]
//[Link][<][master][sword][>][zelda]
//[Link][][][][][master][sword][][zelda]

//②escaped_list_sparator
//专门处理CSV格式(Comma Split Value,逗号分隔值)的分词对象.

//构造声明
escaped_list_separator( char e = '\\', char c = ',', char q = '\"' );

//一般都取默认值,含义如下:
//第一个参数 e 指定了字符串中的转义字符,默认是斜杠/;
//第二个参数是分隔符,默认是逗号;
//第三个参数是引号字符,默认是";

std::string str = "id,100,name,\"mario\"";

boost::escaped_list_separator<char> sep;
boost::tokenizer<escaped_list_separator<char>> tok( str, sep );

print( tok );

//程序运行结果
//[id][100][name][mario]

//③offset_sparator
//其与前两种分词函数对象不同,它分词的功能不基于查找分隔符,而是使用偏移量的概念,
//在处理某些不使用分隔符而使用固定字段宽度的文本时很有用。

//构造声明
template <typename Iter>
offset_separator( iter begin, iter end, bool wrap_offsets = true, bool return_partial_last = true );

//offset_separator的构造函数接收两个迭代器参数(也可以使数组制作)begin和end,指定分词用的整数偏移量序列,
//整数序列的每个元素是分词字段的宽度.

//bool参数bwrapoffsets,决定是否在偏移量用完后继续分词。bool参数return_partial_last决定在偏移量序列
//最后是否返回分词不足的部分。这两个附加参数的默认值都是true.

std::string str = "2233344445";
int offsets[] = {2,3,4};
boost::offset_separator sep( offsets, offsets + 3, true, false );
boost::tokenizer<boost::offset_separator> tok( str, sep );
print( tok );

tok.assign( str, boost::offset_separator(offsets, offsets + 3, false) );
print( tok );

str += "56667";
tok.assign( str, boost::offset_separator(offsets, offsets + 3, true, false) );
print( tok );

//代码中我们用一个数组offsets指定了三个偏移量,要求分割出3个长度分别为2、3、4的单词

//结果如下:
//[22][333][4444][5]
//[22][333][4444]
//[22][333][4444][55][666]

//	请注意输出的第一部分和最后一部分,两者的分词都设置了 return_partial_last 为false,但输出却略不同.
//	这是因为 return_partial_last 只影响偏移量序列的最后一个元素( 即代码中的 offersets[2] = 4 ),对于
//序列中的其他元素则不起作用,无论是否分词不足均输出。所以输出中第一部分的[5]因为它对于偏移量序列的第一个元素,
//所以总能输出,而最后一部分字符串末尾原本应该有输出[7],但因为 return_partial_last 为false 且它对应
//偏移量序列的最后一个元素,所以不被输出.

【tokenizer缺陷】
它只支持使用单个字符进行分词,如果要分解如"||"等多个字符组成的分隔符则无能为力,只能自己定义分词函数对象.



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值