将std :: string解析为坐标?

时间:2017-10-19 21:45:12

标签: c++ string parsing

所以我有一个像这样的字符串(所有正int,方括号中没有空格):

"[(1,2),(10,4),(5,12),... ]"

我想像这样提取int:1,2,10,4,5,12。 我现在使用以下代码,它不处理int> = 10

   std::istringstream coor(coorstring);
   std::vector<int> num;
   char c;
   while (coor.get(c)){
    if (isdigit(c)){
        unsigned int a = c - '0';
        if (a<max) {num.push_back(a);}
    }
   }

例如,我的当前输出为1,2,1,0,4...而不是1,2,10,4...

我很好奇需要修改什么来获得我想要的输出(不使用正则表达式)?顺便说一句,不是使用int vector,而是将这些坐标存储在c ++中以便以后用于绘制图形的好数据结构是什么?

5 个答案:

答案 0 :(得分:1)

我会定义一些自定义operator>>提取运算符来处理这个问题:

typedef std::pair<int, int> point;
typedef std::vector<point> points;

std::istream& operator>>(std::istream &in, point &out)
{
    char ch1, ch2, ch3;
    if (in >> ch1 >> out.first >> ch2 >> out.second >> ch3)
    {
        if ((ch1 != '(') || (ch2 != ',') || (ch3 != ')'))
            in.setstate(std::ios_base::failbit);
    }
    return in;
}

std::istream& operator>>(std::istream &in, points &out)
{
    point pt;
    char ch;

    if (!(in >> ch))
        return in;

    if (ch != '[')
    {
        in.setstate(std::ios_base::failbit);
        return in;
    }

    ch = in.peek();
    do
    {
        if (ch == std::istream::traits_type::eof())
        {
            in.setstate(std::ios_base::failbit);
            break;
        }

        if (ch == ']')
        {
            in.ignore(1);
            break;
        }

        if (ch != '(')
        {
            in.setstate(std::ios_base::failbit);
            break;
        }

        if (!(in >> pt))
            break;

        out.push_back(pt);

        ch = in.peek();
        if (ch == ',')
        {
            in.ignore(1);
            ch = in.peek();
        }
    }
    while (true);

    return in;
}

std::istringstream iss(coorstring);
points coords;
iss >> coords;

live demo

答案 1 :(得分:0)

只需使用字符串拆分:

std::string s = "[(1,2),(10,4),(5,12),... ]";
std::string delimiter = ",";

while ((pos = s.find(delimiter)) != std::string::npos) {
    token = s.substr(0, pos);
    // deal with the data here
    s.erase(0, pos + delimiter.length());
}

它应输出相当规则的数据,所有这些数据都知道:

"[(1", "2)", "(10", "4)", etc...

答案 2 :(得分:0)

您可以使用std::ignore(1000, '(')跳过所有内容,直到(并包括)下一个开头括号,然后使用运算符>>读取第一个坐标,逗号和第二个坐标。

此外,我建议使用数据结构pair来表示一对坐标:

int main() {
    std::istringstream coor("[(1,2),(10,4),(5,12),... ]");
    std::vector<pair<int,int>> coordinates;

    for(;;) {
        coor.ignore(std::numeric_limits<std::streamsize>::max(), '(');
        int x,y;
        char c;
        if (!(coor >> x >> c >> y)) {
            break;
        }
        coordinates.push_back(pair<int,int>(x,y));            
    }

    for (auto coordinate : coordinates) {
        cout << coordinate.first << "/" << coordinate.second << endl;
    }
}

请注意,此解决方案不检查输入字符串的语法,因此它也会接受输入而没有任何右括号或没有括号。但如果语法通过其他方式得到保证,那么它至少是一个简单的解决方案。

答案 3 :(得分:0)

不完全是解决方案,但此时您应该听到的内容:

除了已经存在的工具和功能之外,当您遇到任何问题时,请从以下开始:您自己如何做到这一点?您在脑海中处理了哪些步骤,从纸上的符号到点等概念?如果你遇到一个完全不知道怎么读这个的人,你会怎么解释给他?

另外,请考虑子问题。也许开始一种方法将类似(8,1)的东西转换成一个点然后连接东西。不要害怕编写几十个单独的函数,将一个东西转换成另一个函数。使用不存在的函数然后编写它们。以下是一些可能有助于您学习的代码:

struct Point;

void remove_symbol(string& input, const char symbol);

Point parse_point(const string& input); //"(8,1)" -> Point on that coordinates

vector<string> delimit_by(const string& input, const char delimiter);

没有故意提供实现 - 尝试编写所有这些实现并再次询问它是否无效。一些基本的提示,即使这可能不是最优雅的代码:您可以通过string::length()和[] -operator迭代整数的内容,就像数组一样,您可以通过以下方式将事物追加到字符串中+ =(由于费用昂贵,但开始时很容易)。

(使用STL可能有直接的方法来做这些事情,但是自己编写它们会在开始时给你一些经验,而且你不能知道所有的STL。只要确保了解更多关于STL的信息。 STL从长远来看。)

答案 4 :(得分:0)

简单的两个* -pass算法,产生一个std :: vector / point s:

std::string s = "[(1,2),(10,4),(5,12),... ]";
std::replace_if( s.begin(), s.end(), []( char c ) { return !std::isdigit( c ); }, ' ' );
std::istringstream ss( s );
int x, y;
while (ss >> x >> y)
  points.emplace_back( point( x, y ) );

您可以按照自己喜欢的方式声明point,例如:

struct point
{
  int x, y;
  point(): x(), y() { }
  point( int x, int y ): x(x), y(y) { }
};

* 取决于stringstream构造函数,它可能会再次传递。该算法明确地通过两次。