![]() |
Home | Libraries | People | FAQ | More |
使用這些算法簡單易懂。我們來看看第一個例子:
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace boost;
// ...
string str1(" hello world! ");
to_upper(str1); // str1 == " HELLO WORLD! "
trim(str1); // str1 == "HELLO WORLD!"
string str2=
to_lower_copy(
ireplace_first_copy(
str1,"hello","goodbye")); // str2 == "goodbye world!"
這個例子將 str1 轉換為大寫,並修剪 string 頭尾的空格。然後,以 str1 的拷貝的方式創建 str2,並用 "goodbye" 替換 "hello"。這個例子示範了本庫使用的幾個重要概念:
Container parameters(容器參數):與 STL 算法不同,參數並不一定要用迭代器的方式指定。STL 的慣例具有很大的靈活性,但也有幾個限制。它不可能將算法 stack(套疊)在一起,因為一個容器需要用兩個參數傳遞。因此它就不可能使用另一個算法的返回值。寫成 to_lower(str1),比 to_lower(str1.begin(), str1.end()) 要簡單得多。
Boost.Range 的魔力提供了處理不同 string 類型的統一方法。如果需要傳遞一對迭代器,就可以用 boost::iterator_range 將迭代器打包到一個具有可兼容接口的結構中。
拷貝 vs. 變化:本庫很多算法對輸入執行某種轉換。這種轉換可以在原地進行,改變輸入序列,也可以創建一個轉換後的輸入的拷貝,而保持原始輸入不變。這些可能性中並沒有一種比另一種更加優越,而且各有利弊。因此,本庫同時提供了這兩種方式。
Algorithm stacking(算法套疊):拷貝版本返回一個轉換後的輸入作為結果,這樣就允許將轉換簡單地串接在一個表達式中(例如,我們可以這樣寫 trim_copy(to_upper_copy(s)))。可變版本返回 void,以避免誤用。
Naming(命名):命名遵循來自於標準 C++ 庫的管理。如果同一個算法有拷貝和可變兩個版本,則可變版本沒有後綴,而拷貝版本有後綴 _copy。有些算法有前綴 i(比如 ifind_first())。這個前綴表明這個算法以大小寫無關方式工作。
為使用本庫,需要包含 boost/algorithm/string.hpp 頭文件。如果需要與 regex 相關的函數,則包含 boost/algorithm/string_regex.hpp 頭文件。
STL 有一個轉換字符大小寫的不錯的方法。不幸的是,它只對單個的字符有效,而我們要轉換一個 string,
string str1("HeLlO WoRld!");
to_upper(str1); // str1=="HELLO WORLD!"
to_upper() 和 to_lower() 使用一個指定的地區設置轉換一個 string 中的 characters 的大小寫。
關於更多的信息請參見 boost/algorithm/string/case_conv.hpp 的參考。
本庫的一部分用於處理和 string 相關的判斷式。考慮這個例子:
bool is_executable( string& filename )
{
return
iends_with(filename, ".exe") ||
iends_with(filename, ".com");
}
// ...
string str1("command.com");
cout
<< str1
<< is_executable("command.com")? "is": "is not"
<< "an executable"
<< endl; // prints "command.com is an executable"
//..
char text1[]="hello world!";
cout
<< text1
<< all( text1, is_lower() )? "is": "is not"
<< " written in the lower case"
<< endl; // prints "hello world! is written in the lower case"
判斷式用於判定在各種條件下,一個 substring 是否包含於輸入 string。條件為:一個 string 以這個
substring 開始,以這個 substring 結尾,直接包含這個 substring 以及兩個 string
是否相等。更多的細節請參見 boost/algorithm/string/predicate.hpp 的參考。
另外,算法 all() 檢查一個容器中的所有元素是否滿足由一個判斷式指定的條件。這個判斷式可以是任何一元判斷式,但是本庫提供了一系列有用的 string 相關的判斷式和連接符備用。它們位於 boost/algorithm/string/classification.hpp 頭文件。分類判斷式可以用邏輯連接符連接起來形成一個更複雜的表達式。例如:is_from_range('a','z') || is_digit()。
在解析來自用戶的輸入時,strings 中通常會有不需要的開頭或拖尾字符。為了去掉它們,我們需要修剪函數:
string str1=" hello world! ";
string str2=trim_left_copy(str1); // str2 == "hello world! "
string str3=trim_right_copy(str2); // str3 == " hello world!"
trim(str1); // str1 == "hello world!"
string phone="00423333444";
// remove leading 0 from the phone number
trim_left_if(phone,is_any_of("0")); // phone == "423333444"
它可以修剪一個 string 右邊的,左邊的或兩邊的空格。而且,為了應付移除某些空格以外的東西的需要,有一個 _if 變量,用戶可以指定一個仿函數用來選擇要被移除的 space。它可能使用我們前面提到過的類似 is_digit() 這樣的分類判斷式。請參見 boost/algorithm/string/trim.hpp 的參考。
本庫包含一套查找算法。如下例:
char text[]="hello dolly!";
iterator_range<char*> result=find_last(text,"ll");
transform( result.begin(), result.end(), result.begin(), bind2nd(plus<char>(), 1) );
// text = "hello dommy!"
to_upper(result); // text == "hello doMMy!"
// iterator_range is convertible to bool
if(find_first(text, "dolly"))
{
cout << "Dolly is there" << endl;
}
我們使用 find_last() 在 text 中查找 "ll"。結果以 boost::iterator_range 的形式給出。這個範圍限定了輸入中符合查找規則的部分。在我們的例子中就是最後一次出現的 "ll"。就像我們看到的,find_last() 算法的輸入也可以是 char[],因為這個類型也被 Boost.Range 所支持。接下來的代碼行轉換這個結果。注意 boost::iterator_range 具有通常的 begin() 和 end() 方法,所以它可以像任何其它 STL 容器一樣使用。它也可以轉換為 bool,因此它可以很容易地使用查找算法做一個簡單的包含檢查。
Find algorithms are located in boost/algorithm/string/find.hpp.
查找算法可以用於搜索 string 的一個指定部分。替換則又向前走了一步。在找到一個匹配部分後,用其它東西來取代它。取代的部分根據原始文本計算,並使用了某些轉換。
string str1="Hello Dolly, Hello World!"
replace_first(str1, "Dolly", "Jane"); // str1 == "Hello Jane, Hello World!"
replace_last(str1, "Hello", "Goodbye"); // str1 == "Hello Jane, Goodbye World!"
erase_all(str1, " "); // str1 == "HelloJane,GoodbyeWorld!"
erase_head(str1, 6); // str1 == "Jane,GoodbyeWorld!"
關於替換和刪除函數的完整列表,請參見 參考。有很多預定義的函數用於通常用法,本庫還允許你定義一個定制化的 replace() 來適應一個指定的要求。有一個通用的持有兩個參數的 find_format() 函數。第一個參數是一個 Finder 對象,第二個參數是一個 Formatter 對象。Finder 對象是一個用於執行搜索替換部分的仿函數。Formatter 對像持有 Finder 的結果(通常是一個找到的 substring 的引用)並為它創建一個取代。替換算法將兩者結合起來得到想要的取代。
參見 boost/algorithm/string/replace.hpp,boost/algorithm/string/erase.hpp 和 boost/algorithm/string/find_format.hpp 中的參考。
查找迭代器是對查找算法的一種擴展。不僅僅是找到一個 string 的一個部分。查找迭代器允許我們迭代遍歷匹配指定規則的全部 substring。這個部件使用 Finder 來增量式地搜索 string。解引用一個查找迭代器產生一個 boost::iterator_range 對象,它限定了當前的匹配範圍。
有兩個提供的迭代器是 find_iterator 和 split_iterator。前者迭代遍歷用指定 Finder 找到的全部 substrings。後者迭代遍歷這些 substraings 之間的間隔。
string str1("abc-*-ABC-*-aBc");
// Find all 'abc' substrings (ignoring the case)
// Create a find_iterator
typedef find_iterator<string::iterator> string_find_iterator;
for(string_find_iterator It=
make_find_iterator(str1, first_finder("abc", is_iequal()));
It!=string_find_iterator();
++It)
{
cout << copy_range<std::string>(*It) << endl;
}
// Output will be:
// abc
// ABC
// aBC
typedef split_iterator<string::iterator> string_split_iterator;
for(string_split_iterator It=
make_split_iterator(str1, first_finder("-*-", is_iequal()));
It!=string_split_iterator();
++It)
{
cout << copy_range<std::string>(*It) << endl;
}
// Output will be:
// abc
// ABC
// aBC
注意查找迭代器只有一個模板參數。它是基本的迭代器類型。Finder 在運行時指定。這允許我們為通常的 string 類型 typedef 一個查找迭代器並復用它。另外 make_*_iterator 函數幫助我們為某個特定的範圍創建一個查找迭代器。
請參見 boost/algorithm/string/find_iterator.hpp 中的參考。
分割算法是查找迭代器為一種常用的使用方案所做的擴展。這些算法使用一個查找迭代器並將全部匹配項存儲在提供的容器中。這個容器必須能夠持有被選取的 substrings 的拷貝(比如 std::string)或引用(比如 iterator_range)。
提供了兩個算法。find_all() 在輸入中查找一個 string 的所有拷貝。split() 將輸入分割為若干個部分。
string str1("hello abc-*-ABC-*-aBc goodbye");
typedef vector< iterator_range<string::iterator> > find_vector_type;
find_vector_type FindVec; // #1: Search for separators
ifind_all( FindVec, str1, "abc" ); // FindVec == { [abc],[ABC],[aBc] }
typedef vector< string > split_vector_type;
split_vector_type SplitVec; // #2: Search for tokens
split( SplitVec, str1, is_any_of("-*") ); // SplitVec == { "hello abc","ABC","aBc goodbye" }
[hello] 表示一個限定這個 substring 的 iterator_range。
第一個例子展示如何創建一個持有全部被選取的 substrings 的容器。算法 ifind_all() 將全部以大小寫無關方式等於 "abc" 的 substring 的引用放入 FindVec 中。
第二個例子使用 split() 將 string str1 分割成以字符 '-' 或 '*' 分隔的若干個部分。然後將這些部分放入 SplitVec 中。它還可以指定是否將相鄰的分隔符連接在一起。
更多信息可以在參考 boost/algorithm/string/split.hpp 中找到。
Last revised: February 27, 2008 at 15:00:24 -0500 |