首页IT科技数字怎么转化为字符串c语言(在文字和數字間轉換:boost::lexical_cast « Heresy’s Space)

数字怎么转化为字符串c语言(在文字和數字間轉換:boost::lexical_cast « Heresy’s Space)

时间2025-05-05 12:22:43分类IT科技浏览3047
导读:在文字和數字間轉換:boost::lexical_cast...

在文字和數字間轉換:boost::lexical_cast

2
0
i
給個評價吧~

這一篇是來大概介紹一下 Boost C++ Libraries 裡的 lexical_cast 這個函式庫(官網);他的功能相當簡單            ,主要就是提供了一個 template 函式的介面                  ,來做到任一型別和文字間的轉換            。

很多時候      ,在寫程式的時候            ,我們會需要把字串文字(例如 std::string)的資料轉成數值(例如:double)                  ,或是反過來      ,把數值資料轉成文字;尤其是當要從檔案讀取資料      ,或是要求使用者輸入時                  ,基本上這都是會常常要用到的功能                  。

雖然在標準的 C 或 C++ 裡的確有提供部分的函式            、例如 atoi()(參考)            ,可以快速地做到部分的轉換      ,但是其實都有相當的限制      。例如基本上他們只針對內建的部分型別有提供對應的函式(應該是只有 int                  、long      、double)                  ,而且也沒有反向的轉換(itoa() 並非標準函式            ,要用標準的寫法要用 sprintf(),參考);而另外由於不同的型別就是不同的函示            、也很難寫出統一個方法                  ,來針對轉換的型別做擴充            。

使用 C++ IO Stream

而在標準 C++ 的函式庫裡                  ,實際上他有透過 IO Stream 的概念(參考),提供了 stringstream 這個類別(參考)            ,來進行可自訂的                  、和文字間的轉換                  。像下面就是一個簡單的例子:

#include<stdlib.h> #include<string> #include<sstream> #include<iostream> usingnamespace std; int main( int argc, char** argv ) { // string to float string sTmp = "123.456"; stringstream mSS( sTmp ); float fTmp; mSS >> fTmp; cout << "Convert from string to float: " << fTmp << endl; // float to string fTmp = 1234.567f; stringstream mSS2; mSS2 << fTmp; sTmp = mSS2.str(); cout << "Convert from float to string: " << sTmp << endl; }

第一段的程式碼                  ,基本上就是將 sTmp 這個字串      ,透過 stringstreamoperator>> 來轉換為浮點數 fTmp;而第二段程式碼            ,則是反過來                  ,把 fTmp 這個浮點數      ,轉換成字串      、儲存到 sTmp 這個字串裡      。基本上      ,這邊主要就是透過 stringstream 這個「字串流」來做;而他基本的用法                  ,其實和標準輸入      、輸出的 cout / cin 是一樣的~差別只在於            ,他的資料來源和輸出結果      ,都是字串而已      。

而這邊用的範例是比較簡單                  ,直接用內建的 float                  、string 這兩種型別來作範例;而如果是要擴充到其他的自訂型別的話            ,只要去定義各種型別的 operator<<operator>> 就可以了~下面是一個簡單的範例:

class CVector2 { public: float x; float y; }; istream& operator>>( istream& iS, CVector2& v ) { iS >> v.x >> v.y; return iS; } ostream& operator<<( ostream& oS, const CVector2& v ) { oS << v.x << "/" << v.y; return oS; }

這個範例裡定義了一個 2D 的向量 CVector2            、裡面有 x      、y 兩個 float 的成員變數;另外,也定義了 operator<<operator>> 這兩個全域函式                  ,可以用來處理 CVector2 這個自訂型別與 STL stream 間的運作                  。例如下面就是簡單的範例:

string sTmp = "12 34"; stringstream mSS( sTmp ); CVector2 v; mSS >> v; cout << v << endl;

也就是在針對 CVector2 寫好 operator<<operator>> 後                  ,他就擁有標準的 C++ IO stream 的處理能力了!這點算是相當方便的~

boost::lexical_cast

不過,如果要直接使用 stringstream 來做的話            ,其實在操作上會比較繁瑣                  ,所以 Boost C++ Libraries 就提供了所謂的「lexical_cast」      ,專門來處理這些各種型別和字串間的轉換            。

在使用 lexical_cast 時            ,必須要先加入「#include <boost/lexical_cast.hpp>」;而它的使用基本上非常簡單                  ,就是一個 template 函式      ,他的形式是:

template<typename Target, typename Source> Target lexical_cast(const Source &arg);

而使用上      ,如果直接修改這篇文章第一個使用 stringstream 的程式的話                  ,就會變成下面的形式      。

// string to float string sTmp = "123.456"; float fTmp = boost::lexical_cast<float>( sTmp ); cout << "Convert from string to float: " << fTmp << endl; // float to string fTmp = 1234.567f; sTmp = boost::lexical_cast<string>( fTmp ); cout << "Convert from float to string: " << sTmp << endl;

基本上            ,只要把要轉換的資料當參數傳進去      ,在指定要轉換的目標型別                  ,就可以了!他省去了所有對於 stringstream 的操作            ,而直接用一個統一的函式來做,在許多時候會是相當方便的~

而如果要讓自訂的型別也可以適用於 lexical_cast 的話                  ,來源的型別(Source)和目標的型別(Target)分別需要符合一些條件:

來源型別必須要是「OutputStreamable」                  ,也就是有定義 std::ostreamstd::wostreamoperator<<                  。 目標型別必須要是「InputStreamable」,也就是要有針對 std::istreamstd::wistream 定義 operator>>            。 目標型別必須要有 default constructor 和 copy constructor。

所以基本上            ,只要有針對自己定義的型別                  ,也定義出 IO Stream 的 operator<<operator>>      ,應該就可以用了!

一些小細節

不過實際上 Heresy 在用的時候            ,還是有遇到一些問題                  。像以前面 CVector2 的例子來說                  ,雖然已經有定義了 operator<<operator>>      ,但是還是會有問題的!像下面的例子      ,想直接使用 lexical_cast 把字串 sTmp 轉換成為 CVector2 的話                  ,語法雖然沒問題            ,但是在執行時是會出錯的!

string sTmp = "12 34"; CVector2 v = boost::lexical_cast< CVector2 >( sTmp );

主要的原因呢      ,應該是由於 Boost 的 lexical_cast 會去設定使用的 istreamnoskipws                  、不忽略空白(參考);而也因此                  ,才會造成 istream& operator>>( istream& iS, CVector2& v ) 這個函式在直接使用 stringstream 的時候因為預設會略調空白的資料            、而可以正常運作            ,但是使用 lexical_cast 時卻因為特別把空白也抓出來做處理了,反而造成轉換的錯誤                  。

而解決方法呢?其實也滿簡單的                  ,只要在進行處理前                  ,先強制設定回 skipws 應該就可以了~修正後的函式,也就變成了:

istream& operator>>( istream& iS, CVector2& v ) { iS >> std::skipws >> v.x >> v.y; return iS; }

理論上            ,這樣應該就不會有問題、可以直接用 lexical_cast 來處理自訂的 CVector2 了~

不過另外要注意的是                  ,實際上 Boost 的 lexical_cast 在做處理的時候      ,做了很多例外狀況的判斷                  、處理            ,算是相當嚴謹的;而也因此                  ,他的效能並不會特別好!有興趣的話      ,可以參考看看《Very poor boost::lexical_cast performance》這串討論。不過基本上      ,由於它的效率真的比較差一些                  ,所以如果是轉換的效能很重要的話            ,建議還是換比較快的方法來寫會比較合適            。

声明:本站所有文章      ,如无特殊说明或标注                  ,均为本站原创发布                  。任何个人或组织            ,在未征得本站同意时,禁止复制                  、盗用、采集            、发布本站内容到任何网站                  、书籍等各类媒体平台      。如若本站内容侵犯了原著者的合法权益                  ,可联系我们进行处理            。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
vue单文件组件 一定要webpack吗(Vue3学习-第二章 单文件组件(SFC)) macbookpro如何调整字体大小(苹果Macbook Pro分辨率怎么调想把屏幕上的字体显示变大小)