<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          字符串算法(string_algorithm)

          共 12916字,需瀏覽 26分鐘

           ·

          2021-06-07 08:17

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

            作者 |  stingliang

          來源 |  urlify.cn/veaARn

          format

          作用

          格式化輸出對象,可以不改變流輸出狀態(tài)實(shí)現(xiàn)類似于printf()的輸出

          頭文件

          #include <boost/format.hpp>
          using namespace boost;

          簡單的例子

          //第一種用法
          cout << format("%s:%d+%d=%d\n") %"sum" %1 %2 %(1+2);
          //第二種用法
          format fmt("(%1% + %2%) * %2% = %3%\n");
          fmt %2 %5;
          fmt %((2+5)*5);
          cout << fmt.str();

          運(yùn)行結(jié)果:

          sum:1+2=3
          (2 + 5) * 5 = 35

          說明:

          1. 第一種用法使用了和printf類似的語法結(jié)構(gòu),不必贅述

          2. 第二種用法,先實(shí)例化format對象確定輸出格式,使用%N%指示參數(shù)位置

          format對象操作

          //返回格式化后的字符串
          formatobj.str();
          //返回已格式化的字符串長度
          formatobj.size();
          //清空格式和內(nèi)容
          formatobj.parse();
          //只清除格式
          formatobj.clear();

          格式化規(guī)則

          • %05d:輸出寬度為5的整數(shù),不足位用0填充

          • %-8.3f:輸出左對齊,寬度總為8,小數(shù)位為3的浮點(diǎn)數(shù)

          • % 10s:輸出10位的字符串,不足用空格填充

          • 05X:輸出寬度為5的大寫16進(jìn)制整數(shù),不足填充0

          • %|spec|:將格式化選項(xiàng)包含進(jìn)兩個(gè)豎線之間,更好的區(qū)分格式化選項(xiàng)和普通字符

          • %N%:標(biāo)記弟N個(gè)參數(shù),相當(dāng)于占位符,不帶任何其他的格式化選項(xiàng)

          format fmt1("%05d\t%-8.3f\t% 10s\t%05X\n");
          cout << fmt1 %62 %2.236 %"123456789" %48;
          format fmt2("%|05d|\t%|-8.3f|\t%| 10s|\t%|05X|\n");
          cout << fmt2 %62 %2.236 %"123456789" %48;

          執(zhí)行結(jié)果:

          00062   2.236            123456789      00030
          00062   2.236            123456789      00030

          lexical_cast

          功能

          對字符串進(jìn)行“字面值”的轉(zhuǎn)換,對字符串與整數(shù)/浮點(diǎn)數(shù)之間進(jìn)行轉(zhuǎn)換

          需要包含的頭文件

          #inlude <boost/lexical_cast.hpp>
          using namespace boost;

          聲明

          //標(biāo)準(zhǔn)形式,轉(zhuǎn)換數(shù)字和字符串
          template <typename Target,typename Source>
          inline Target lexical_cast(const Source &arg);

          //轉(zhuǎn)換C字符串
          template <typename Target>
          inline Target lexical_cast(const char * chars,std::size_t count)

          使用

          在模板參數(shù)里指定轉(zhuǎn)換的目標(biāo)類型即可

          //string -> int
          int x = lexical_cast<int> ("100");

          // string -> float
          float pai = lexical_cast<float> ("3.14159e5");

          //int -> string
          string str = lexical_cast<string> (456);

          //float -> string
          string str = lexical_cast<string> (0.618);

          //hex -> string
          string str = lexical_cast<string> (0x10);

          【注意事項(xiàng)】
          該模板智能轉(zhuǎn)換字面值,如果出現(xiàn)不合理的轉(zhuǎn)換,例如“hello”轉(zhuǎn)int類型,則會報(bào)錯(正常人應(yīng)該不會這么干)

          錯誤處理

          當(dāng)lexical_cast無法執(zhí)行轉(zhuǎn)換操作時(shí)會拋出異常bad_lexical_cast,它是std::bad_cast的派生類

          傳統(tǒng)保護(hù)辦法

          在使用lexical_cast時(shí)應(yīng)該使用try_catch來保護(hù)代碼

          try
          {
              cout <<lexical_cast<int>("0x100");
          }
          catch(bad_lexical_cast& e)
          {
              cout << "error: \n" << e.what() << endl;
          }

          //運(yùn)行結(jié)果
          error: 
          bad lexical cast:source type value could not be interpreted as target

          已有庫的保護(hù)辦法

          需要使用命名空間:boost::conversion

          函數(shù):

          boost::conversion::try_lexical_cast(typeRaw,typeTarget);

          返回值為bool表示是否轉(zhuǎn)換成功

          【技巧:驗(yàn)證數(shù)字字符串的合法性(用于驗(yàn)證用戶輸入的有效性)】

          實(shí)現(xiàn)一個(gè)模板類

          template<typename T>
          bool num_valid(const char* str)
          {
              T tmp;
              return conversion::try_lexical_convert(str,tmp)  //嘗試轉(zhuǎn)換數(shù)字
          }

          //用法
          assert(num_valid<double>("3.14"));
          assert(!num_valid<int>("3.14"));
          assert(num_valid<int>("65535"));

          轉(zhuǎn)換要求

          lexical_cast對轉(zhuǎn)換對象有一定要求

          • 轉(zhuǎn)換的起點(diǎn)對象是可流輸出的(可以用“<<”)

            【注意事項(xiàng)】對于重載了“<<”操作符的自定義類型也可以使用它

          • 轉(zhuǎn)換的終點(diǎn)對象是可流輸入的(可以用“>>”)

          • 轉(zhuǎn)換的終點(diǎn)對象是可默認(rèn)構(gòu)造的、可拷貝構(gòu)造的

          最常用的搭檔:int,double,string等POD類型

          C++標(biāo)準(zhǔn)轉(zhuǎn)換函數(shù)

          //字符串轉(zhuǎn)換為數(shù)字
          int stoi(const string& str,size_t *idx = 0,int base = 10);
          long stol(const string& str,size_t *idx = 0,int base = 10);
          long long stoll(const string& str,size_t *idx = 0,int base = 10);
          float stof(const string& str,size_t *idx = 0);
          double stod(const string& str,size_t *idx = 0);

          //數(shù)字轉(zhuǎn)換為string
          string to_string(Type val);

          【注意事項(xiàng)】必須以空格或數(shù)字開頭,否則報(bào)錯

          和lexical_cast的比較:

          優(yōu)點(diǎn):

          • 無需寫模板參數(shù)

          • 允許出現(xiàn)非數(shù)字字符(忽略起始空格,遇到無法轉(zhuǎn)換的字符終止)

          缺點(diǎn):

          • 不支持對自定義類型的轉(zhuǎn)換

          string_algo

          功能

          提供了強(qiáng)大的字符串處理能力,如查找、訪問、基本的字符串處理

          頭文件和命名空間

          #include <boost/algorithm/string.hpp>

          using namespace boost;

          用法

          【注意事項(xiàng)】不僅可以用在string上(在這里string被看作是vector<char>),也可以用于部分其他容器,例如(vector<T>

          大小寫轉(zhuǎn)換

          string str("Hello");

          //轉(zhuǎn)向大寫
          cout << to_upper(str) << endl;    //這種方式會改變源數(shù)據(jù)
          cout << to_upper_copy(str) << endl;    //這種方法返回一個(gè)轉(zhuǎn)換后的拷貝對象

          //轉(zhuǎn)向小寫
          cout << to_lower(str) <<endl;
          cout << to_lower_copy(str) << endl;

          判斷式(算法)

          • lexicographical_compare:根據(jù)字典順序檢測一個(gè)字符串是否小于另一個(gè)字符串

          • starts_with:檢測字符串是否以另一個(gè)字符串為前綴

          • ends_with:檢測字符串是否以另一個(gè)字符串為后綴

          • contains:檢測字符串是否包含另一個(gè)字符串

          • equals:檢測兩個(gè)字符串是否相等

          • all:檢測字符串是否滿足指定的判斷式

          【注意事項(xiàng)】

          • 除了all以外都有一個(gè)i前綴的版本,表示大小寫無關(guān)

          • 這些函數(shù)都不變動字符串

          用法示例

          string str("Power Bomb");

          assert(iends_with(str,"bomb"));    //大小寫無關(guān)檢測后綴
          assert(!ends_with(str,"bomb"));    //大小寫敏感檢測后綴

          assert(starts_with(str,"Pow"));    //檢測前綴

          assert(contains(str,"er"));    //測試包含關(guān)系

          string str2 = to_lower_copy(str);    //轉(zhuǎn)換成小寫
          assert(iequals(str,str2));    //大小寫無關(guān)判斷相等

          assert(ilexicographical_compare(str,str3));    //大小寫無關(guān)字符串比較

          assert(all(str2.substr(0,5),is_lower()));    //檢測字符串均小寫

          分類

          提供一組分類函數(shù),用于檢測字符串是否符合某種特性,主要搭配其他算法使用,如上一節(jié)的all

          • is_space:字符是否為空格或制表符(tab)

          • is_alnum:字符是否為字母和數(shù)字字符

          • is_alpha:字符是否為字母

          • is_cntrl:字符是否為控制字符

          • is_digit:字符是否為十進(jìn)制數(shù)字

          • is_graph:字符是否為圖形字符

          • is_lower:字符是否為小寫字符

          • is_print:字符是否為可打印字符

          • is_punct:字符是否為標(biāo)點(diǎn)符號字符

          • is_upper:字符是否為大寫字符

          • is_xdigit:字符是否為十六進(jìn)制數(shù)字

          • is_any_of:字符是否是參數(shù)字符序列中的任意字符

          • if_from_range:字符是否位于指定區(qū)間內(nèi),即from<=ch<=to

          需要注意的是這些函數(shù)并不真正地檢測字符,而是返回一個(gè)類型為detail::is_classifiedF的函數(shù)對象,這個(gè)函數(shù)對象的operator()才是真正的分類函數(shù)(因此,這些函數(shù)都屬于工廠函數(shù))。

          修剪

          提供三個(gè)算法,刪去字符串開頭結(jié)尾的空格,提供_copy后綴和_if后綴

          • trim_left:刪除左邊的空格

          • trim_right:刪除右邊的空格

          • trim:刪除兩邊的空格

          用法示例

          format fmt("|%s|\n");

          string str = "  samus aran  ";
          cout << fmt % trim_copy(str);    //刪除兩端的空格
          cout << fmt % trim_left_copy(str);    //刪除左邊的空格

          trim_right(str);    //原地刪除
          cout << fmt % str;

          string str2 = "2020 Happy new Year!!!";
          cout << fmt % trim_left_copy_if(str2,is_digit());    //刪除左端的數(shù)字
          cout << fmt % trim_right_copy_if(str2,is_punct());    //刪除右邊的標(biāo)點(diǎn)
          //刪除兩端的標(biāo)點(diǎn)、數(shù)字和空格
          cout << fmt % trim_copy_if(str2,is_punct() || is_digit() || is_space()); 

          執(zhí)行結(jié)果

          |samus aran|
          |samus aran  |
          |  samus aran|
          | Happy new Year!!!|
          |2020 Happy new Year|
          |Happy new Year|

          查找

          提供的查找算法如下:

          • find_first:查找字符串在輸入中第一次出現(xiàn)的位置

          • find_last:查找字符串在輸入中最后一次出現(xiàn)的位置

          • find_nth:查找字符串在輸入中的第N次(從0開始計(jì)數(shù))出現(xiàn)的位置

          • find_head:取一個(gè)字符串開頭N個(gè)字符的子串,相當(dāng)于substr(0,n)

          • find_tail:取一個(gè)字符串末尾N個(gè)字符的子串

          【注意事項(xiàng)】

          這些算法的返回值是iterator_range,在概念上類似于std::pair,包裝了兩個(gè)迭代器,可以用begin()end()訪問。提供了i前綴的用法。
          用法示例

          format fmt("|%s|.pos = %d\n");
          string str = "Long long ago , there was a king.";
          iterator_range<string::iterator> rge;    //迭代器區(qū)間

          rge = find_first(str,"long");    //找第一次出現(xiàn)
          cout << fmt % rge % (rge.begin() - str.begin());

          rge = ifind_first(str,"long");    //大小寫無關(guān)第一次出現(xiàn)
          cout << fmt % rge % (rge.begin() - str.begin());

          rge = find_nth(str,"ng",2);    //找第三次出現(xiàn)
          cout << fmt % rge % (rge.begin() - str.begin());

          rge = find_head(str,4);    //取前4個(gè)字符
          cout << fmt % rge % (rge.begin() - str.begin());

          rge = find_tail(str,5);    //取末5個(gè)字符
          cout << fmt % rge % (rge.begin() - str.begin());

          rge = find_first(str,"samus");    //找不到
          assert(rge.empty() && !rge);

          執(zhí)行結(jié)果

          |long|.pos = 5
          |Long|.pos = 0
          |ng|.pos = 30
          |Long|.pos = 0
          |king.|.pos = 28

          替換與刪除

          替換、刪除操作與查找算法非常接近,是在查找到結(jié)果后再對字符串進(jìn)行處理,具體如下:

          replace/erase_first:替換/刪除字符串在輸入中的第一次出現(xiàn)

          replace/erase_last:替換/刪除字符串在輸入中的最后一次出現(xiàn)

          replace/erase_nth:替換/刪除字符串在輸入中的第n次出現(xiàn)

          replace/erase_all:替換/刪除字符串在輸入中的所有出現(xiàn)

          replace/erase_head:替換/刪除輸入的開頭

          replace/erase_tail:替換/刪除輸入的末尾

          前8個(gè)算法每個(gè)都有前綴i、后綴_copy的組合,有四個(gè)版本,后4個(gè)則只有后綴_copy的兩個(gè)版本

          示例代碼如下:

          // 替換和刪除
          string str_2 = "Samus beat the monster.\n";
          // replace
          cout << replace_first_copy(str_2, "Samus""samus");
          replace_last(str_2, "beat""kill");
          cout << str_2;
          replace_tail(str_2, 9, "ridley.\n");
          cout << str_2;
          // delete
          cout << ierase_all_copy(str_2, "samus ");
          cout << replace_nth_copy(str_2, "l", 1, "L");
          cout << erase_tail_copy(str_2, 8);

          運(yùn)行結(jié)果:

          samus beat the monster.
          Samus kill the monster.
          Samus kill the ridley.
          kill the ridley.
          Samus kilL the ridley.
          Samus kill the

          分割

          string_algo提供了兩個(gè)字符串分割算法:find_all(雖然它的名稱含有find,但因?yàn)槠涔δ芏粴w類為分割算法)和split,可以使用某種策略把字符串分割成若干部分,并將分割后的字符串拷貝存入指定的容器。

          分割算法對容器類型的要求是必須能夠持有查找到結(jié)果的拷貝或引用,因此容器的元素類型必須是stringiterator_range<string::iterator>,容器則可以是vector、list、deque等標(biāo)準(zhǔn)容器。

          find_all算法類似于普通的查找算法,它搜索所有匹配的字符串,將其加入容器,有一個(gè)忽略大小寫的前綴i版本。

          split算法使用判斷式Pred來確定分割的依據(jù),如果字符ch滿足判斷式Pred(Pred(ch)==true),那么它就是一個(gè)分割符,將字符串從這里分割。

          還有第三個(gè)參數(shù)eCompress可以取值為token_compress_ontoken_compress_off,如果值為前者,那么當(dāng)兩個(gè)分隔符連續(xù)出現(xiàn)時(shí),它們將被視為一個(gè)分隔符,如果值為后者則兩個(gè)連續(xù)的分隔符標(biāo)記了一個(gè)空字符串。參數(shù)eCompress的默認(rèn)取值為token_compress_off

          string str = "Samus, Link.Zelda::Mario-Luigi+zelda";

          deque<string> d;
          // 大小寫無關(guān)查找
          ifind_all(d, str, "zELDA");
          assert(d.size() == 2);
          for(auto x: d)
          {
              cout << "[" << x << "]";
          }
          cout << endl;

          // 存儲range對象
          list<iterator_range<string::iterator>> l;
          split(l, str, is_any_of(",.:-+"));  // 使用標(biāo)點(diǎn)分割
          for(auto x: l)
          {
              cout << "[" << x << "]";
          }
          cout << endl;

          l.clear();
          split(l, str, is_any_of(",.:-+"), token_compress_on);
          for(auto x: l)
          {
              cout << "[" << x << "]";
          }
          cout << endl;

          程序運(yùn)行結(jié)果如下:

          [Zelda][zelda]
          [Samus][ Link][Zelda][][Mario][Luigi][zelda]
          [Samus][ Link][Zelda][Mario][Luigi][zelda]

          合并

          合并算法join是分割算法的逆運(yùn)算,它把存儲在容器中的字符串連接成一個(gè)新的字符串,并且可以指定連接的分隔符。

          join還有一個(gè)后綴_if的版本,它接收一個(gè)判斷式,只有滿足判斷式的字符串才能合并。

          vector<string> v = list_of("Samus")("Link")("Zelda")("Mario");
          cout << join(v, "+") << endl;
          cout << join_if(
              v, "**",
              [](string_ref s)
              {
                  return contains(s, "a");
              }
          ) << endl;

          程序首先使用assign庫向vector添加了4個(gè)字符串,然后用+合并它們。隨后的join_if算法使用lambda表達(dá)式定義了一個(gè)簡單的謂詞,它包裝了算法contains,判斷字符串是否包含字符a。
          程序運(yùn)行結(jié)果如下:

          Samus+Link+Zelda+Mario
          Samus**Zelda**Mario

          string_ref

          功能

          一種輕量級的string,持有string類型的引用

          頭文件

          #include <boost/utility/string_ref.hpp>
          using namespace boost;

          類摘要

          template<typename charT,typename traits>
          class basic_string_ref
          {
              public:
                  //和std::string有著幾乎一樣的接口
              private:
                  const charT* ptr_;    //字符串指針
                  std::size_t len_;     //字符串長度
          };

          不拷貝字符串,所以不分配內(nèi)存,使用兩個(gè)成員變量表示字符串

          用法

          【注意事項(xiàng)】只能像std::string&一樣去獲取其內(nèi)容,但不能修改其本身

          1、構(gòu)造

          //通過標(biāo)準(zhǔn)字符數(shù)組構(gòu)造普通string,有拷貝成本
          const char* ch = "hello";
          string str(ch);

          //字符數(shù)組構(gòu)造,無成本
          string_ref s1(ch);

          //標(biāo)準(zhǔn)字符串構(gòu)造,無成本
          string_ref s2(str);

          可以像使用普通string一樣使用string_ref(除了修改)

          2、用在哪

          用于代替string&作為函數(shù)參數(shù)和返回值,可以完全避免字符串拷貝代價(jià)












          瀏覽 60
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线免费观看黄色电影 | 欧洲激情网 | 伊人无码在线 | 国产伊人网在线观看 | 久久人人妻人人人人妻性色aV |