將數字轉換為文字,反之亦然,這是一個常見的問題,因為它在許多不同的情況下都很有用,並且 C++98 沒有提供專門用於解決此問題的工具。
幸運的是,C++ 是一種通用語言,因此它可以非常容易地解決這個問題,而且,像大多數事情一樣,您有很多方法可以完成這項任務。
這裡列出了一些
目錄
C++ - 字串流
C++ 流庫功能強大,可以輕鬆進行格式化的輸入輸出操作。使用 字串流,您可以對字串執行此輸入/輸出,這使您可以將數字(或任何具有 <<
>>
流運算子過載的型別)與字串之間進行轉換。
使用 stringstreams
,您可以使用相同的語法來轉換不同的數字型別。
要使用 stringstreams
,您需要 #include <sstream>
數字到字串
使用字串流將數字轉換為字串需要兩個步驟
- 將數字的值輸出到流
- 獲取包含流內容的字串
由於此轉換隻需要流的輸出操作,因此可以使用
ostringstream
(輸出字串流)代替用於輸入和輸出的流(
stringstream
)
這是一個顯示每個步驟的示例
1 2 3 4 5 6 7 8 9 10 11
|
int Number = 123; // number to be converted to a string
string Result; // string which will contain the result
ostringstream convert; // stream used for the conversion
convert << Number; // insert the textual representation of 'Number' in the characters in the stream
Result = convert.str(); // set 'Result' to the contents of the stream
// 'Result' now is equal to "123"
|
此操作可以縮短為單行
1 2
|
int Number = 123;
string String = static_cast<ostringstream*>( &(ostringstream() << Number) )->str();
|
這裡構造了一個未命名的字串流物件並執行了輸出
ostringstream() << Number
然後,由於 << 返回對
ostream
(
ostringstream
的基類)的引用,因此操作的結果需要強制轉換回字串流
static_cast<ostringstream*>
最後,我們將結果流的內容作為字串
->str()
獲取,並將該值分配給字串
string String =
自定義格式
字串流允許使用
操縱器 和
區域設定來自定義這些操作的結果,因此您可以輕鬆更改結果字串的格式
示例:- 這不是一個完整的程式 -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
// Headers needed:
#include <iomanip>
#include <locale>
#include <sstream>
#include <string> // this should be already included in <sstream>
// Defining own numeric facet:
class WithComma: public numpunct<char> // class for decimal numbers using comma instead of point
{
protected:
char do_decimal_point() const { return ','; } // change the decimal separator
};
// Conversion code:
double Number = 0.12; // Number to convert to string
ostringstream Convert;
locale MyLocale( locale(), new WithComma);// Crate customized locale
Convert.imbue(MyLocale); // Imbue the custom locale to the stringstream
Convert << fixed << setprecision(3) << Number; // Use some manipulators
string Result = Convert.str(); // Give the result to the string
// Result is now equal to "0,120"
|
字串到數字
同樣,透過字串流將字串轉換為數字也需要兩個步驟
- 從字串構造流
- 將值讀入變數
為此(因為您需要從流中讀取輸入),將使用
istringstream
雖然數字始終可以轉換為字串,但字串必須有效才能轉換為數字(例如:嘗試將
"hello"
轉換為整數肯定會失敗),因此在此轉換中,必須進行一些檢查
這是程式碼示例
1 2 3 4 5 6 7 8 9 10 11
|
string Text = "456"; // string containing the number
int Result; //number which will contain the result
istringstream convert(Text); // stringstream used for the conversion constructed with the contents of 'Text'
// ie: the stream will start containing the characters of 'Text'
if ( !(convert >> Result) ) //give the value to 'Result' using the characters in the stream
Result = 0; //if that fails set 'Result' to 0
//'Result' now equal to 456
|
此轉換更容易簡化為單行
1 2 3
|
string Text = "456";
int Number;
if ( ! (istringstream(Text) >> Number) ) Number = 0;
|
在上面的程式碼中,一個 istringstream 物件從“Text”構造
istringstream(Text)
,其內容被讀入數字變數
>> Number
。
如果該操作失敗
if ( !
,則“Number”設定為零
Number = 0;
區域設定和操縱器也可以像任何流一樣使用
更復雜的情況
通用的
stringstream
(可以用於輸入和輸出)在某些更復雜的情況下以及在幾乎所有需要執行
string
未提供的操作的情況下都很有用
簡單示例函式
這裡列出了一些使用字串流執行這些轉換的函式
1 2 3 4 5 6 7
|
template <typename T>
string NumberToString ( T Number )
{
ostringstream ss;
ss << Number;
return ss.str();
}
|
用法:
NumberToString ( Number );
1 2 3 4 5 6 7
|
template <typename T>
T StringToNumber ( const string &Text )
{
istringstream ss(Text);
T result;
return ss >> result ? result : 0;
}
|
用法:
StringToNumber<Type> ( String );
注意:在程式碼示例中,省略了 std:: 以簡化程式碼
使用最後一個函式,無法檢測轉換是否成功或失敗
C++11
C++11 引入了一些標準庫函式,可以直接轉換
基本型別到 std::string 物件,反之亦然。
std::to_string 將基本數字型別轉換為字串。
函式集
stoi、stol、stoll 轉換為整數型別,函式
stof、stod、stold 轉換為浮點值。
這些函式在 <string> 中宣告。
請注意,由於這些函式是在最新版本的 C++ 標準中新增的,
除非您的實現非常新,否則它們可能不可用。
1 2 3 4 5
|
int number = 123;
string text = to_string(number);
text = "456"
number = stoi(number);
|
C++ - Boost 庫
使用字串流是執行這些轉換的標準 C++ 方法,但它們通常需要幾行程式碼
在 Boost 庫中,有一個 lexical_cast
,它允許透過簡單的函式呼叫執行字串流轉換
要使此庫正常工作,只需包含標頭檔案,無需連結
1 2 3 4 5 6 7 8
|
// Boost header needed:
#include <boost/lexical_cast.hpp>
// Number to string conversion:
Text = boost::lexical_cast<string>(Number);
// String to number conversion:
Number = boost::lexical_cast<Type>(Text);
|
上面的示例不處理最終的轉換失敗
當
boost::lexical_cast
失敗時,它會丟擲
boost::bad_lexical_cast
(派生自
std::bad_cast
)
1 2 3 4 5 6 7 8 9 10 11
|
try
{
Number = boost::lexical_cast<Type>(Text);
}
catch ( const boost::bad_lexical_cast &exc ) // conversion failed, exception thrown by lexical_cast and caught
{
Number = 0; // give 'Number' an arbitrary value ( in this case zero )
// if you don't give it any value, it would maintain the value it had before the conversion
// A string containing a description of the exception can be found in exc.what()
}
|
C - stdio
數字到字串
在 C 中沒有流庫,但函式
sprintf
可用於轉換
它的工作方式類似於
printf
,但它會將字元放入 C 字串(字元陣列)而不是
stdout
。使用它不如使用流那麼容易,因為格式字串會根據需要轉換的數字型別而變化
示例
1 2 3 4 5
|
int Number = 123; // number to convert
char Result[16]; // string which will contain the number
sprintf ( Result, "%d", Number ); // %d makes the result be a decimal integer
|
字串到數字
與
printf
一樣,
scanf
也有一個相關函式,可以從字元陣列中讀取資料,即
sscanf
1 2 3 4 5
|
char Text[] = "456"; // string to be converted
int Result; // number which will contain the result
sscanf ( Text, "%d", &Result );
|
如果
sscanf
失敗(即:字串不是數字),則傳遞的變數的值保持不變,在這種情況下,該函式應返回零,因為沒有引數被成功讀取,如果傳遞的字串非常糟糕,以至於無法從中讀取任何內容,它將返回
EOF
1 2 3 4 5 6 7 8
|
char Text[] = "456"; // string to be converted
int Result; // number which will contain the result
int Succeeded = sscanf ( Text, "%d", &Result );
if ( !Succeeded || Succeeded == EOF ) // check if something went wrong during the conversion
Result = 0;
|
C - stdlib
stdlib 標頭包含一些用於轉換文字和數字的函式
請注意,其中一些函式不是標準的! 這些函式是
- 有關示例,請參閱各個參考頁面 -
編寫您自己的函式
使用現有的庫更容易更好,但只是為了展示上述一些解決方案的工作原理,這裡有一些示例,說明如何僅使用核心語言編寫將文字轉換為數字以及將數字轉換為文字的函式,以下示例來自圖書“The C Programming Language”
這是 itoa
(Integer TO Alphabet)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
/* itoa: convert n to characters in s */
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
|
這是
itoa
中使用的函式
reverse
1 2 3 4 5 6 7 8 9 10 11 12
|
/* reverse: reverse string s in place */
void reverse(char s[])
{
int i, j;
char c;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
|
reverse
使用標頭 cstring 中的函式
strlen
(C 中的 string.h)
這很容易實現,這是一個例子
1 2 3 4 5 6 7 8
|
/* strlen: return length of s */
int strlen(char s[])
{
int i = 0;
while (s[i] != '\0')
++i;
return i;
}
|
正如您所看到的,可以使用一些基本的 C 建立一個(糟糕的)轉換函式
同樣的道理也適用於相反的轉換
1 2 3 4 5 6 7 8 9
|
/* atoi: convert s to integer */
int atoi(char s[])
{
int i, n;
n = 0;
for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i)
n = 10 * n + (s[i] - '0');
return n;
}
|
當然,這些函式因多種原因而不好,不應在實際程式碼中使用
它們只是展示了整數值和字元序列之間轉換背後的思想