将数字转换为文本,反之亦然,这是一个常见的问题,因为它在许多不同的情况下都很有用,并且 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;
}
|
当然,这些函数因多种原因而不好,不应在实际代码中使用
它们只是展示了整数值和字符序列之间转换背后的思想