split years in string

Hello, if i have years in string something like
 
string years = "2001,2008,2015-2017";


how can i split it into array of strings ?
array[0] = 2001
array[1] = 2008
array[2] = 2015
array[3] = 2016
array[4] = 2017
Hi

You could use getchar() to read character by character, compare if it is ',' or a digit, if its a digit store it in the array position, if its ',' move to the next position in the array, any other character in the input will finish the read

Here is an example

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
34
#include <stdio.h>
#include <math.h>
#include <string.h>
using namespace std;


int main()
{

    char inputStr;
    int years[100], i=0;
    memset(years,0,sizeof(years));

    while (1)
    {
        inputStr = getchar();
        if(inputStr == ',')
        {
            i++;
            inputStr = getchar();
        }

        if(((inputStr < '0') || (inputStr > '9'))&&(inputStr != ','))
            break;

        years[i] = (years[i]*10) + inputStr - '0';

    }
    for (int j=0;j<=i;j++)
        printf("%d\n",years[j]);

    return 0;
}


in the line

years[i] = (years[i]*10) + inputStr - '0';

you need to multiply *10 in order to move the digit to the right position so if your input is:

2001,2001,2003

You read first 2
Compare if its a digit, coma or other character
As is a digit you store it in years[0]
You use the -'0' because you are reading characters so the digits will be read as ASCII code
Then you read the next input 0
Compare if its a digit, coma or other character
As is a digit you store it in years[0]
Then you multiply the previous 2*10 so you move the 2 to the tens position and store the 0 in the units and so on...

My first thought was that the string should be split at each comma. That means in some cases the resulting substring would be a single year, and in others it could be a range, separated by a hyphen. That is possibly a good idea, it matches the meaning of the data.

But on the other hand, if the string is simply treated as a list of integers delimited by a some character other than space, it become simpler, but some of the inherent meaning is lost.

1
2
3
4
5
6
7
8
9
10
11
12
    string input = "2001,2008,2015-2017";
       
    int year;
    char ch;
    
    istringstream ss(input);    // use a stringstream to parse the contents

    while (ss >> year)          // read an integer
    {
        cout << year << endl;  
        ss >> ch;               // read and ignore a non-whitespace character
    }


To Chervil: Thats works, but i get this
2001
2008
2015
2017

and i need this

2001
2008
2015
2016
2017
I see. I misunderstood the requirement. If I understand correctly, the string 2015-2017 needs to be interpreted as a range, and all the years from the first to the last value will be required.

You may be able to build something based upon this idea:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    string input = "2001,2008,2015-2017";

    istringstream ss(input);
    string line;
    while (getline(ss, line, ','))
    {
        size_t pos;
        if ((pos = line.find('-')) == string::npos)
        {
            cout << "single:   " << line << endl;
        }
        else
        {
            cout << "range from: "
                 << line.substr(0, pos)
                 << " to "
                 << line.substr(pos+1) << endl;
        }
    }

Output:
single:   2001
single:   2008
range from: 2015 to 2017


You would need to enhance the code to handle the range, first by converting the substring into an int, and then by some sort of loop to generate all the values in the range.
Last edited on
well i post here whole code:

i party solve it. Now it works if i have string like "2001,2008,2015-2017", "2001,2008,2009,2010,2011,2015-2017" etc.

but it must work also when i have it only in range like "2020-2030" or something like this "2020-2030, 2043, 2047-2050" and i have no idea how i should do it, i try almost everything what i know :/

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#ifndef __PROGTEST__
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;

#define EASTER_OK                0
#define EASTER_INVALID_FILENAME  1
#define EASTER_INVALID_YEARS     2
#define EASTER_IO_ERROR          3


#endif /* __PROGTEST__ */


const char *HEADER =
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"> <html>\n"
"<head>\n"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> <title>C++</title>\n"
"</head>\n"
"<body>\n"
"<table width=\"300\">\n"
"<tr><th width=\"99\">day</th><th width=\"99\">month</th><th width=\"99\">year</th></tr>\n";

const char *FOOTER =
"</table>\n"
"</body>\n"
"</html>\n";

int checkname(const char * outFileName)
{

    if(strlen(outFileName)<=5)
        return EASTER_INVALID_FILENAME;

    string fn = outFileName;
    if(fn.substr(fn.find_last_of(".") + 1) == "html")
    {
    return EASTER_OK;

    } else
    {
    return EASTER_INVALID_FILENAME;
    }

}

int checkyear(const char * years){
    int yearsv=0;
    yearsv = atoi(years);
    if((yearsv > 1582) && (yearsv < 2200))
    return EASTER_OK;
    else return EASTER_INVALID_YEARS;

}

int easterReport ( const char * years, const char * outFileName )
 {
    if(checkname(outFileName) != EASTER_OK)
        return EASTER_INVALID_FILENAME;

    string rokys = years;
    string rokyz = years;
    char c;
    char prvni[5];
    char druhy[5];
    int j = 4;
    cout << rokys;
    int interval = 0;
    int intervalsingle = 0;
    int vysinter = 0;
    int rokypole[1000];
    char rokpole[4];
    int quantu = 0;
    int iuantu = 0; // pocet cisel
    int puantu = 0; // pocet roku


    for (unsigned int i = 0; i < rokys.size();i++)
    {
        c = years[i];


        if ((c == ',' )&& (rokys.at(i+1) == ',' || rokys.at(i+1) == '-'))
        {
        return EASTER_INVALID_YEARS;
        }
        if ((c == '-' )&& (rokys.at(i+1) == ',' || rokys.at(i+1) == '-'))
        {
        return EASTER_INVALID_YEARS;
        }

        if (c >= '0' && c <= '9')
        {
        rokyz.at(i) = c;
        rokpole[quantu] = c;
        quantu++;
        }

        else if (c == ',')
        {
        rokyz.at(i) = ',';
        }

        else if (c == ' ')
        {

        }

        else if (c == '-')
        {
        rokyz.at(i) = '-';
        interval++;

       /* for (int q = 0; q < 4; q++)
        {
        prvni[q] = rokyz.at(i-j);

        j--;
        }
        j++;
        for (int q = 0; q < 4; q++)
        {
        druhy[q] = rokyz.at(i+j);

        j++;
        }
        cout << '\n';
        cout << prvni << endl;
        cout << druhy << endl;
        int paprika = atoi(prvni);
        int jablko  = atoi(druhy);
        interval = jablko - paprika;
        cout << interval;
        */
        }

        else
        {
        return EASTER_INVALID_YEARS;
        }
        if(quantu == 4)
        {
        rokypole[iuantu]= atoi(rokpole);
        iuantu++;
        puantu++;
        intervalsingle++;
        quantu = 0;
        }

    }

    cout << "single interval je:" << intervalsingle-2;
    interval = intervalsingle-2;

    if(interval != 0)
    {
    vysinter = rokypole[interval+1]-rokypole[interval];


    int pocet = interval;
    cout <<endl;
    cout << "interval "<< interval<<endl;
    cout << "vysledek intervalu  " <<vysinter<<endl;
    for(int o = 0; o <= vysinter; o++)
    {
        rokypole[interval+o] = rokypole[interval]+o;
        pocet++;
    }

    for(int i = 0; i < pocet; i++)
    {
       cout <<  rokypole[i]<<endl;
    }
    cout << "pocet cisel je: " << pocet << '\n';
    }
    else
        {
    cout << endl;
    for(int i = 0; i < iuantu; i++)
    {
       cout <<  rokypole[i]<<endl;
    }

        }

/*
    string input = "2015,2016,2017,2018,2019,2017,2018,2019, 2020-2030";
    cout << '\n';
    istringstream ss(input);
    string line;
    while (getline(ss, line, ','))
    {
        size_t pos;
        if ((pos = line.find('-')) == string::npos)
        {
            cout << "single:   " << line << endl;
        }
        else
        {
            cout << "range from: "
                 << line.substr(0, pos)
                 << " to "
                 << line.substr(pos+1) << endl;
        }
    }
*/
    if(checkyear(years) != EASTER_OK)
        return EASTER_INVALID_YEARS;

    return EASTER_OK;
 }

#ifndef __PROGTEST__
int main ()
 {
    int s = easterReport( "2001, 2020-2030", "g.html" );
    printf("\nreturn code: %d\n",s);
    return EASTER_OK;
 }
#endif /* __PROGTEST__ */ 
If I understand correctly, you want this sort of result?
2001,2008,2015-2017
2001
2008
2015
2016
2017


2020-2030
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030


2020-2030, 2043, 2047-2050
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2043
2047
2048
2049
2050


I was disappointed to read, "i have no idea how i should do it", the output above was produced by following the idea I put forward in my previous post.
yes thats what i want, "2020-2030, 2043, 2047-2050" have int array where every year will be on one place in array as array[0] = "2020", array[1] = "2021" etc.
I trying use your idea but nothing work for 100% :(
Topic archived. No new replies allowed.