简体   繁体   中英

C++ simple string parsing and save to ints

I have a string that look like this,

x:12812Y:121Z:1292

where there is always "X:","Y:", and "Z:" I need to convert the numerals following each letter into a int variable, thus

int x = 12812
int y = 121
int y = 1292

Is there a way to do it? Thanks!

Yes there is a way to do it:

Read two characters (the X: part), then read an integer. Repeat two more times.

If the "string" is in a file, I first recommend you read the whole line from the file into an std::string (using eg std::getline ), then use std::istringstream to extract the data of each line.

If the order of the data is not fixe (eg X may not always be first) then check the first character to see what data the number is.

If the order is always fixed and the same, you can also store the number in an array or a vector.

using standard scanf is as simple as this:

#include<cstdio>

int main() {
    int x, y, z;
    char xx, yy, zz;
    scanf("%c:%d%c:%d%c:%d", &xx, &x, &yy, &y, &zz, &z);
    printf("%d %d %d\n", x, y, z);
    return 0;
}

If the order and format is always fixed you could do something like this:

 string str="x:12812Y:121Z:1292";//you might want to convert this to uppercase first

 string xword,yword,zword;

istringstream ss(&str[1]);//put the string read in to string stream, jump the first x

//you may want to this in a loop
::getline(ss,xword,'Y');//will getthe x part,something like :12812
::getline(ss,yword,'Z');//get the y part, the y will not be read here, something like :121
::getline(ss,zword,'X');//get the z part

xword.erase(0,1);//remove the leading colon
yword.erase(0,1);//remove the leading colon
zword.erase(0,1);//remove the leading colon

 // convert the string to int

Try this:

#include<iostream>
#include<sstream>
#include<string>

int main()
{
    std::string str = "x:12812Y:121Z:1292";
    std::string::size_type sz;
    std::stringstream ss(str);
    char tmp;
    int x, y, z;

    ss>>tmp;
    ss>>tmp;
    ss>>x;
    ss>>tmp;
    ss>>tmp;
    ss>>y;
    ss>>tmp;
    ss>>tmp;
    ss>>z;

    std::cout<<"x:"<<x<<"\n";
    std::cout<<"y:"<<y<<"\n";
    std::cout<<"z:"<<z<<"\n";

    return 0;
}

Output:

x:12812
y:121
z:1292

Some things can be done surprisingly elegantly without relying on a library. This code demonstrates using the next_int function. next_int only takes up 9 lines -- the rest of the code demonstrates use with wide-character C-string, a char C-string and a std::string (through a C-string from std::string::c_str()).

#include <iostream>
#include <string>

// next_int parses a non-negative decimal integer value
// beginning at or after the passed string pointer.
// The pointer is incremented to point to the character
// which follows the parsed digits.
// If no digits follow the passed pointer, a value of
// zero is returned and the pointer is advanced to the
// string's terminating nul.
template <typename C>
inline int next_int(const C* &p) {
    while(*p && (*p < C('0') || *p > C('9'))) { ++p; }
    int val = 0;
    while(*p >= C('0') && *p <= C('9')) {
        val = val * 10 + *(p++) - C('0');
    }
    return val;
}

int main() {
    const auto* pws = L"x:12812Y:121Z:1292";;
    int x = next_int(pws);
    int y = next_int(pws);
    int z = next_int(pws);
    std::cout << "(" << sizeof(*pws) << " Wide String) x: " << x << "  y: " << y << "  z: " << z << '\n';

    const char* pcs = "54321,891011,0,1";
    std::cout << "\n* char String\n";
    for(int index=0; *pcs; ++index) {
        const int value = next_int(pcs);
        std::cout << "    " << index << ": " << value << '\n';
    }

    // This example shows what happens when no digits follow the pointer
    // passed to next_int.  Because no digits appear in the characters 
    // following the final "10", the last call to next_int returns 0.
    // next_int could be modified to unambiguously enumerate arbitrarily-sized
    // sets of numbers, possibly by returning a magic number (like -1) if
    // val was never updated by a digit, or adding a second scan, advancing
    // p to the next digit or nul character, thus skipping the phantom
    // parse at the end.
    std::string nums = "Flight 552 to Paris cost me $400 1-way and lasted 10 hours";
    const auto* pstr = nums.c_str();
    std::cout << "\n* char String from std::string\n";
    std::cout << "  The extra 0 at the end comes from passing next_int a string containing no digits\n";
    for(int index=0; *pstr; ++index) {
        const int value = next_int(pstr);
        std::cout << index << ": " << value << '\n';
    }
}

This is the output:

(2 Wide String) x: 12812  y: 121  z: 1292

* char String
    0: 54321
    1: 891011
    2: 0
    3: 1

* char String from std::string
  The extra 0 at the end comes from passing next_int a string containing no digits
0: 552
1: 400
2: 1
3: 10
4: 0

Assuming that keys are case-sensitive letters, values are always integers and relationship between key and value is important, but order of key/value pairs is not.

#include <string>
#include <sstream>
#include <iostream>

int main()
{
    std::istringstream ss("x:12812Y:121Z:1292");

    int x, Y, Z;

    while (!ss.eof())
    {
        char tag, delim;
        int val;

        ss >> tag >> delim >> val;

        switch(tag)
        {
            case 'x': x = val; break;
            case 'Y': Y = val; break;
            case 'Z': Z = val; break;
        }
    }

    std::cout << "parsed: x=" << x << " Y=" << Y << " Z=" << Z << std::endl;
    return 0;
},

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM