c++ - 带有格式化字符串的 istream 提取值

标签 c++ text formatting iostream istream

我在 istream 中有这个格式化的字符串。

(5, -4)

假设:

  1. 左括号
  2. 一个整数
  3. 逗号和空格
  4. 另一个整数
  5. 右括号

我想知道提取两个整数和验证字符串格式的最佳方法是什么。

这是在这样的类中:

class MyPoint
{
public:
   MyPoint() = default;
   ~MyPoint() = default;
   ...
   friend ostream & operator>>(ostream & lhs, MyPoint const & rhs);
   ...
private:
   int x, y;
};

ostream & operator>>(ostream & lhs, MyPoint const & rhs) {
    // ???
}

非常感谢大家。

这是我的头文件

#ifndef MYPOINT_H
#define MYPOINT_H

#include <iostream>
using namespace std;

class MyPoint
{
public:
    MyPoint() : mX{ 0 }, mY{ 0 } { ; }
    MyPoint(int x, int y) : mX{ x }, mY{ y } { ; }
    ~MyPoint() = default;

    int x() const { return mX; }
    int y() const { return mY; }
    void setX(int x) { mX = x; }
    void setY(int y) { mY = y; }

    MyPoint operator-() const { return MyPoint(-mX, mY); }
    MyPoint operator+(MyPoint rhs) const { rhs.mX += mX; rhs.mY += mY; return rhs; }
    MyPoint operator-(MyPoint rhs) const { rhs.mX = mX - rhs.mX; rhs.mY = mY - rhs.mY; return rhs; }
    MyPoint operator*(MyPoint rhs) const { rhs.mX *= mX; rhs.mY *= mY; return rhs; }
    MyPoint operator/(MyPoint rhs) const { rhs.mX = mX / rhs.mX; rhs.mY = mY / rhs.mY; return rhs; }
    MyPoint operator%(MyPoint rhs) const { rhs.mX = mX % rhs.mX; rhs.mY = mY % rhs.mY; return rhs; }

    friend MyPoint operator+(int lhs, MyPoint const & rhs);
    friend MyPoint operator-(int lhs, MyPoint const & rhs);
    friend MyPoint operator*(int lhs, MyPoint const & rhs);
    friend MyPoint operator/(int lhs, MyPoint const & rhs);
    friend MyPoint operator%(int lhs, MyPoint const & rhs);

    friend ostream & operator<<(ostream & lhs, MyPoint const & rhs);
    friend istream & operator>>(istream & lhs, MyPoint & rhs);

private:
    int mX, mY;

};

#endif //MYPOINT_H

这是我的源文件

#include "MyPoint.h"


MyPoint operator+(int lhs, MyPoint const & rhs) {
    return MyPoint(lhs + rhs.mX, lhs + rhs.mY);
}
MyPoint operator-(int lhs, MyPoint const & rhs) {
    return MyPoint(lhs - rhs.mX, lhs - rhs.mY);
}
MyPoint operator*(int lhs, MyPoint const & rhs) {
    return MyPoint(lhs * rhs.mX, lhs * rhs.mY);
}
MyPoint operator/(int lhs, MyPoint const & rhs) {
    return MyPoint(lhs / rhs.mX, lhs / rhs.mY);
}
MyPoint operator%(int lhs, MyPoint const & rhs) {
    return MyPoint(lhs % rhs.mX, lhs % rhs.mY);
}

ostream & operator<<(ostream & lhs, MyPoint const & rhs) {
    return lhs << "(" << rhs.mX << "," << rhs.mY << ")";
}
istream & operator >> (istream & lhs, MyPoint & rhs) {
    return lhs >> "(" >> rhs.mX >> "," >> rhs.mY >> ")"; // HERE is the compiling error
}

最后,主要的测试

MyPoint p1, p2(2, -2);
cout << p1 << endl;
cout << p2 << endl;

有了这个文件,我得到了这个错误: 错误 C2679 二进制“>>”:未找到采用“const char [2]”类型右手操作数的运算符(或没有可接受的转换)

最佳答案

对于这种情况,我经常发现定义 operator>> 的重载很方便从流中读取预定义的字符串:

std::istream &operator>>(std::istream &is, char const *pat) {

    char ch;
    while (isspace(static_cast<unsigned char>(is.peek())))
        is.get(ch);

    while (*pat && is && *pat == is.peek() && is.get(ch)) {
        ++pat;
    }

    // if we didn't reach the end of the pattern, matching failed (mismatch, premature EOF, etc.)
    if (*pat) {
        is.setstate(std::ios::failbit);
    }

    return is;
}

有了这个,阅读你的格式可能看起来像这样:

istream & operator>>(istream & lhs, MyPoint & rhs) {
    return lhs >> "(" >> rhs.x >> "," >> rhs.y >> ")";
}

这将像大多数典型的重载一样,如果您提供的模式不匹配,则设置流的失败位。就目前而言,输入中的每个字符串前面都可以有任意空格(就像数字等的转换一样)。

这里有一个技术上的小错误:就目前而言,它使用了全局区域设置的空白定义。真正正确的是,它可能应该使用与输入流关联的语言环境中提供的定义。

另请注意,我必须更改您对 operator>> 的定义少量;在这个问题中,它看起来像是 operator<< 的重载, 仅将这两个字符更改为 operator>>相反。

举个简单的例子:

#include <iostream>

std::istream &operator>>(std::istream &is, char const *pat) {
    // implementation above
}

class Point {
    int x, y;

    friend std::istream &operator>>(std::istream &is, Point &p) { 
        return is >> "(" >> p.x >>"," >> p.y >> ")";
    }

    friend std::ostream &operator<<(std::ostream &os, Point const &p) { 
        return os << "(" << p.x <<", " << p.y << ")";
    }
};

int main() {
    Point p;

    std::cout << "Please enter a point: ";
    std::cin >> p;
    std::cout << "Thanks. Point: " << p << '\n';
}

使用 VC++ 2013、VC++ 2015 和 g++ 6.1 进行了测试(但这根本没有突破编译器的极限,所以我希望它能正常工作,即使编译器太老了,它们通常都被严重破坏了(例如,gcc 2.x 或 VC++ 6.0)。

关于c++ - 带有格式化字符串的 istream 提取值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39835621/

相关文章:

c++ - 提高 QTimer 的准确性

c++ - 错误的 cv::putText 结果

cocoa - 在区域设置更改时进行禁用的格式化 NSTextField 更新?

r - 如何将特定时间格式转换为 R 中的时间戳?

jquery - 通过 jQuery 传递文本字符串

java - 如何使用 KeyEvent 只允许 JTextField 中的数字?

c++ - 三向快速排序需要更高的性能

c++ - 用于基准代码运行 K 次的 Unix 命令

javascript - 限制 Javascript 打印输出中的字符

c++ - 如何在 C++ 中读取和解析 CSV 文件?