C ++中是否有用于在字符串中选择数字的函数
Is there an function in C++ for picking numbers inside a string
我有一个来自 C++ 堆栈的计算器,当我尝试在上面插入一个公式时,比如 1+2*3 我希望我有一个函数可以获取数字,直到每个不是数字的字符.
示例 12+2 它会得到 12,然后会跳过 +,因为代码会进入其他部分,然后再次得到数字 2。
我做了类似
的东西
for(i=0;i++;i<string.size();)
{
if(string[i]<48)
character(string[i]);
else if (string[i]>=48)
number(string[i]);
}
但这效率不高,有人知道它的功能吗?
如果它只适用于整数,您可以使用 stdlib 中的常绿 atoi() 这是文档 https://www.cplusplus.com/reference/cstdlib/atoi/,还有 atof() 和 atol() 相同但使用双精度和长整型
首先,你的foor loop
是完全错误的。在任何 C++ 资源(例如 https://www.w3schools.com/cpp/cpp_for_loop.asp)中,您会看到只有 3 个语句:
for (statement 1; statement 2; statement 3) {}
语句 1 在代码块执行之前执行(一次)。
语句 2 定义执行代码块的条件。
代码块执行后(每次)执行语句 3。
其次,何不试试is_alpha()?我认为这将回答您的问题。当然你仍然需要遍历字符串。
第三个 - 在线有大量此类计算器的示例。随便看看。
您的意思是像 std::stoi
,但跳过所有非数字而不仅仅是空格?
通常的解决方案是先将字符串标记化为子字符串,例如 {"1", "+", "2", "*", "3"}
,然后对标记进行适当的转换。之后尝试将您的数字 1, 2, 3
与您的运算符 +,*
重新组合似乎很混乱且容易出错。
顺便说一句,在你的代码中使用像 48
这样的幻数是糟糕的风格,原因有很多:
- 无论如何,重复的幻数不是一个好主意,因为它很难阅读,而且很容易将其中一个误输入为 49,并且很难找到它
- 如果您真的必须对
0
的 ASCII 代码进行硬编码,请考虑 0x30
而不是 48
- 数字的十六进制值更具可读性 IMO
- 但 ASCII 是一个平台细节(尽管是一个相当普遍的细节),因此最好不要对其进行硬编码
- 无论如何你不需要自己编写任何字符分类无论编码:只需使用
isdigit
等-这就是它们的用途
没有一种功能可以满足您的需求,但对它的支持仍然比大多数人意识到的要多。当你从流中读取一个数字时,它知道在数字之前跳过白色 space,所以即使流包含类似“1234”的东西,你也可以只读取一个整数,并得到 1234
。
反过来,流使用区域设置来告诉它什么是白色或不是白色 space,因此在它尝试读取数字时应该被忽略。反过来,语言环境基本上只是方面的集合。用于对字符是否为白色进行分类的方面 space 是 ctype
方面。
所以,为了得到我们想要的,我们需要一个 ctype
facet 将所有字符分为两类:数字和白色 space。为此,我们可以这样做:
struct digits_only: std::ctype<char> {
digits_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
// a table with one entry for each possible value of char.
// we'll start with it classifying everything as whitespace:
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
// now fill in the digits to say they're digits:
std::fill_n(&rc['0'], 10, std::ctype_base::digit);
return &rc[0];
}
};
然后我们需要创建一个流,告诉流使用具有该方面的语言环境(称为“注入”流)然后我们可以读取我们的数据,就好像它包含的所有数字一样:
int main()
{
std::string input("1+2*3/(44+55)");
std::istringstream buf(input);
buf.imbue(std::locale(std::locale(), new digits_only()));
int value;
while (buf >> value) // just read numbers from the stream
std::cout << value << '\n';
}
[我稍微修饰了一下字符串(添加了一些括号和几个两位数)]
结果相当乏味,但显示了(我相信)您的要求:
1
2
3
44
55
我有一个来自 C++ 堆栈的计算器,当我尝试在上面插入一个公式时,比如 1+2*3 我希望我有一个函数可以获取数字,直到每个不是数字的字符. 示例 12+2 它会得到 12,然后会跳过 +,因为代码会进入其他部分,然后再次得到数字 2。 我做了类似
的东西for(i=0;i++;i<string.size();)
{
if(string[i]<48)
character(string[i]);
else if (string[i]>=48)
number(string[i]);
}
但这效率不高,有人知道它的功能吗?
如果它只适用于整数,您可以使用 stdlib 中的常绿 atoi() 这是文档 https://www.cplusplus.com/reference/cstdlib/atoi/,还有 atof() 和 atol() 相同但使用双精度和长整型
首先,你的foor loop
是完全错误的。在任何 C++ 资源(例如 https://www.w3schools.com/cpp/cpp_for_loop.asp)中,您会看到只有 3 个语句:
for (statement 1; statement 2; statement 3) {}
语句 1 在代码块执行之前执行(一次)。
语句 2 定义执行代码块的条件。
代码块执行后(每次)执行语句 3。
其次,何不试试is_alpha()?我认为这将回答您的问题。当然你仍然需要遍历字符串。
第三个 - 在线有大量此类计算器的示例。随便看看。
您的意思是像 std::stoi
,但跳过所有非数字而不仅仅是空格?
通常的解决方案是先将字符串标记化为子字符串,例如 {"1", "+", "2", "*", "3"}
,然后对标记进行适当的转换。之后尝试将您的数字 1, 2, 3
与您的运算符 +,*
重新组合似乎很混乱且容易出错。
顺便说一句,在你的代码中使用像 48
这样的幻数是糟糕的风格,原因有很多:
- 无论如何,重复的幻数不是一个好主意,因为它很难阅读,而且很容易将其中一个误输入为 49,并且很难找到它
- 如果您真的必须对
0
的 ASCII 代码进行硬编码,请考虑0x30
而不是48
- 数字的十六进制值更具可读性 IMO - 但 ASCII 是一个平台细节(尽管是一个相当普遍的细节),因此最好不要对其进行硬编码
- 无论如何你不需要自己编写任何字符分类无论编码:只需使用
isdigit
等-这就是它们的用途
没有一种功能可以满足您的需求,但对它的支持仍然比大多数人意识到的要多。当你从流中读取一个数字时,它知道在数字之前跳过白色 space,所以即使流包含类似“1234”的东西,你也可以只读取一个整数,并得到 1234
。
反过来,流使用区域设置来告诉它什么是白色或不是白色 space,因此在它尝试读取数字时应该被忽略。反过来,语言环境基本上只是方面的集合。用于对字符是否为白色进行分类的方面 space 是 ctype
方面。
所以,为了得到我们想要的,我们需要一个 ctype
facet 将所有字符分为两类:数字和白色 space。为此,我们可以这样做:
struct digits_only: std::ctype<char> {
digits_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
// a table with one entry for each possible value of char.
// we'll start with it classifying everything as whitespace:
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
// now fill in the digits to say they're digits:
std::fill_n(&rc['0'], 10, std::ctype_base::digit);
return &rc[0];
}
};
然后我们需要创建一个流,告诉流使用具有该方面的语言环境(称为“注入”流)然后我们可以读取我们的数据,就好像它包含的所有数字一样:
int main()
{
std::string input("1+2*3/(44+55)");
std::istringstream buf(input);
buf.imbue(std::locale(std::locale(), new digits_only()));
int value;
while (buf >> value) // just read numbers from the stream
std::cout << value << '\n';
}
[我稍微修饰了一下字符串(添加了一些括号和几个两位数)]
结果相当乏味,但显示了(我相信)您的要求:
1
2
3
44
55