Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
illya05
139 / 95 / 19
Регистрация: 03.08.2013
Сообщений: 764
#1

Парсинг строки по пробелам - C++

03.04.2016, 22:42. Просмотров 549. Ответов 12
Метки нет (Все метки)

Делаю консоль. Написал парсер команд:
C++
1
2
3
string command[5] = {""};
int i = 0;
while(i < 5){ command[i] = ""; i++;}
При этом команда по пробелам заноситься в массив. Работает это так:
- download http://example.com/1.txt 1.txt
заноситься в массив как "download", "http://example.com/1.txt" и "1.txt"

Но если вводить путь с пробелами, то получается баг
- download http://example.com/folder name/1.txt 1.txt
"download", "http://example.com/folder", "name/1.txt" и "1.txt"

Как сделать так, что-бы если брать путь в кавычки, то он не будет разрываться по пробелам?
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
03.04.2016, 22:42
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Парсинг строки по пробелам (C++):

Добавление разделения строки по пробелам в код - C++
#include &quot;stdafx.h&quot; #include &lt;iostream&gt; #include &lt;clocale&gt; #include &lt;string.h&gt; using namespace std; char text = {}, q =...

Разделить строку по пробелам (без потоков) - C++
Здравствуйте. Я решаю задачку из книги, надо написать небольшую оболочку. Использую Linux. Думаю над тем, как разделить строку (команду),...

Разделить строку по пробелам и записать полученные части в массив - C++
Здравствуйте. Подскажите, есть ли способ разделить строку по пробелам и записать полученные части в массив (по сути, аналог Split() в c#)?

Парсинг строки - C++
Доброе время суток! столкнулся с такой проблемой что странно отрекаются данные из строки bool LoadTypeFiles() { ...

Парсинг строки С++ - C++
Ребят,нигде не нашел ничего дельного,прошу,чтобы натолкнули на мысль или объяснили что,да как. В общем на вход,к примеру,поступает строка...

Парсинг строки - C++
Добрый день. Помогите с решением следующей задачи. На вход идет строка из 0 и 1, например, 110100011, нужно распарсить её на составляющие....

12
hoggy
6701 / 2883 / 494
Регистрация: 15.11.2014
Сообщений: 6,480
Завершенные тесты: 1
03.04.2016, 23:23 #2
http://rextester.com/KNDX73583
C++
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
#include <iostream>
#include <vector>
#include <string>
 
// ============================================================================
// ============================================================================
 
    /* разбивает строку на токены, с учетом символов пунктуации */ 
 
namespace lex{
 
    namespace tokenizeDetail {
        template<class Ch> struct default_ { const char* delimiters()    { return  " "; } };
        template<> struct default_<wchar_t>{ const wchar_t* delimiters() { return L" "; } };
    } //namespace tokenizeDetail 
 
    #define dDEFAULT \
        tokenizeDetail::default_<typename Str::value_type>::delimiters()
 
    template <class Str, class Callback, class CallbaclD>
    void tokenize(const Str& text, Callback&& callback, CallbaclD&& callbackD, 
        const Str& delimiters = dDEFAULT, bool trimEmpty = true)
    {
        #undef dDEFAULT
        typename Str::size_type pos, lastPos = 0;
        for(;;)
        {
            pos = text.find_first_of(delimiters, lastPos);
            if(pos == Str::npos)
            {
                pos = text.length();
                if(pos != lastPos || !trimEmpty)
                    callback(text.data()+lastPos, pos-lastPos);
                break;
            }
            else if(pos != lastPos || !trimEmpty)
                callback(text.data() + lastPos, pos-lastPos),
                callbackD(text[pos]);
            else
                callbackD(text[pos]);
        
            lastPos = pos + 1;
        }
    }
} // namespace lex
 
// ============================================================================
// ============================================================================
 
 
void add(std::vector<std::string>& dst, const char q)
{
    if (dst.empty())
        dst.emplace_back(q,1);
    else
        dst.back() += q;
}
 
void add(std::vector<std::string>& dst, const char* p, size_t len)
{
    if (dst.empty())
        dst.emplace_back(p,len);
    else
        dst.back() += std::string(p,len);
}
 
 
std::vector<std::string> words(const std::string& line)
{
    std::vector<std::string> result;
    enum eSTATE { eNONE, eBEG, eEND };
    eSTATE st = eNONE;
    const std::string punctuation = " \"";
 
    const auto processWords = [&result, &st](const char* p, size_t len)
    { 
        switch (st)
        {
            case eNONE: result.emplace_back(p,len); return;
            case eBEG : add(result, p,len); return;
            case eEND : add(result, p,len); return;
        }
    };
    
    const auto processPunctuation = [&result, &st](const char ch)
    { 
        if(ch=='"')
        {
            switch (st)
            {
                case eNONE: st = eBEG; add(result, '"'); return;
                case eBEG:  st = eEND; add(result, '"'); return;
                case eEND:  st = eBEG; add(result, '"'); return;
            }
        }
        else if(st == eEND)
            st = eNONE;
    };
    lex::tokenize(line, processWords, processPunctuation, punctuation, true);
    return result;
}
 
 
int main()
{
    std::cout << "Hello, world!\n";
    
    const std::string src 
        = "download http://example.com/\"folder name\"/1.txt 1.txt";
    
    for(const auto& word: words(src))
        std::cout << "word: '" << word << "'\n";
}
1
illya05
139 / 95 / 19
Регистрация: 03.08.2013
Сообщений: 764
03.04.2016, 23:33  [ТС] #3
hoggy, Спасибо, но как в командной строке весь путь должен быть в кавычках, а не только часть с пробелом:
Код
download "http://example.com/folder name/1.txt" 1.txt
1
hoggy
6701 / 2883 / 494
Регистрация: 15.11.2014
Сообщений: 6,480
Завершенные тесты: 1
04.04.2016, 00:30 #4
большое спасибо за верное замечание.

исправленная версия:

http://rextester.com/RTWD4372




C++
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
#include <iostream>
#include <vector>
#include <string>
 
// ============================================================================
// ============================================================================
 
    /* разбивает строку на токены, с учетом символов пунктуации */ 
 
namespace lex{
 
    namespace tokenizeDetail {
        template<class Ch> struct default_ { const char* delimiters()    { return  " "; } };
        template<> struct default_<wchar_t>{ const wchar_t* delimiters() { return L" "; } };
    } //namespace tokenizeDetail 
 
    #define dDEFAULT \
        tokenizeDetail::default_<typename Str::value_type>::delimiters()
 
    template <class Str, class Callback, class CallbaclD>
    void tokenize(const Str& text, Callback&& callback, CallbaclD&& callbackD, 
        const Str& delimiters = dDEFAULT, bool trimEmpty = true)
    {
        #undef dDEFAULT
        typename Str::size_type pos, lastPos = 0;
        for(;;)
        {
            pos = text.find_first_of(delimiters, lastPos);
            if(pos == Str::npos)
            {
                pos = text.length();
                if(pos != lastPos || !trimEmpty)
                    callback(text.data()+lastPos, pos-lastPos);
                break;
            }
            else if(pos != lastPos || !trimEmpty)
                callback(text.data() + lastPos, pos-lastPos),
                callbackD(text[pos]);
            else
                callbackD(text[pos]);
        
            lastPos = pos + 1;
        }
    }
} // namespace lex
 
// ============================================================================
// ============================================================================
 
void to_new(std::vector<std::string>& dst, const char* p, size_t len)
    { dst.emplace_back(p,len); }
void to_new(std::vector<std::string>& dst, const char ch)
    { dst.emplace_back(1,ch); }
void to_new(std::vector<std::string>& dst)
    { dst.emplace_back(); }
 
void to_back(std::vector<std::string>& dst, const char q)
{
    if (dst.empty())
        to_new(dst, q);
    else
        dst.back() += q;
}
 
void to_back(std::vector<std::string>& dst, const char* p, size_t len)
{
    if (dst.empty())
        to_new(dst, p, len);
    else
        dst.back() += std::string(p,len);
}
 
 
 
 
std::vector<std::string> words(const std::string& line)
{
    std::vector<std::string> result;
    enum eSTATE { eNONE, eBEG, eEND, eBWORD };
    eSTATE st = eNONE;
    const std::string punctuation = " \"";
 
    const auto processWords = [&result, &st](const char* p, size_t len)
    { 
        switch (st)
        {
            case eBEG  : to_back(result, p,len); break;
            case eEND  : to_back(result, p,len); break;
            case eNONE : to_new (result, p,len); st = eBWORD; break;
            case eBWORD: to_new (result, p,len); st = eNONE ; break;
        }
    };
    
    const auto processPunctuation = [&result, &st](const char ch)
    { 
        #define dIGNORE_QUOTE
 
        if(ch=='"')
        {
            switch (st)
            {
                #ifdef dIGNORE_QUOTE
                case eBWORD: st = eBEG; to_new(result); break;
                case eNONE : st = eBEG; break;
                case eBEG  : st = eEND; break;
                case eEND  : st = eBEG; break;
                #else
                case eBWORD: st = eBEG; to_new (result, '"'); break;
                case eNONE : st = eBEG; to_back(result, '"'); break;
                case eBEG  : st = eEND; to_back(result, '"'); break;
                case eEND  : st = eBEG; to_back(result, '"'); break;
                #endif
            }
        }
        else
        {
            switch (st)
            {
                case eBEG:  to_back(result, ch); break;
                case eEND:  st = eNONE; break;
            }
        }
    };
 
    lex::tokenize(line, processWords, processPunctuation, punctuation, true);
    return result;
}
 
 
int main()
{
    std::cout << "Hello, world!\n";
 
    {
        const std::string src 
            = "download http://example.com/\"folder name\"/1.txt 1.txt";
 
        std::cout << "---------------------------------------------------------------\n"
            << src << std::endl;
 
        for(const auto& word: words(src))
            std::cout << "word: '" << word << "'\n";
    }
    
    
    {
        const std::string src 
            = "download \"http://example.com/folder name/1.txt\" 1.txt";
 
        std::cout << "---------------------------------------------------------------\n"
            << src << std::endl;
        
        for(const auto& word: words(src))
            std::cout << "word: '" << word << "'\n";
    }
 
    {
        const std::string src 
            = "download \"http://example.com/folder name/1.txt\"\"\" 1.txt";
 
        std::cout << "---------------------------------------------------------------\n"
            << src << std::endl;
        
        for(const auto& word: words(src))
            std::cout << "word: '" << word << "'\n";
    }
}
1
illya05
139 / 95 / 19
Регистрация: 03.08.2013
Сообщений: 764
04.04.2016, 00:48  [ТС] #5
hoggy, Огромное спасибо! Всего наилучшего Вам!

Добавлено через 4 минуты
hoggy, последний вопрос, если можно. Как в этот for добавить условие (ci < cn)?
0
hoggy
6701 / 2883 / 494
Регистрация: 15.11.2014
Сообщений: 6,480
Завершенные тесты: 1
04.04.2016, 00:53 #6
Цитата Сообщение от illya05 Посмотреть сообщение
Как в этот for добавить условие (ci < cn)?
C++
1
2
3
4
std::vector<std::string> result = words(src);   
const auto count = result.size();
for(size_t n=0; n<size; ++n )
    std::cout << "word: '" << result[n] << "'\n";
1
illya05
139 / 95 / 19
Регистрация: 03.08.2013
Сообщений: 764
04.04.2016, 01:00  [ТС] #7
hoggy, вызывает исключение прав доступа чтения.

Может я не так выразился, но мне нужно примерно это:
C++
1
2
3
4
5
6
7
8
const int cn = 5;
string command[cn] = {""};
 
int ci = 0;
for(const auto& word : words(temp) && ci < cn){
    command[ci] = word;
    ci++;
}
Но этот синтаксис for я вижу впервые и не могу исправить ошибку
0
hoggy
6701 / 2883 / 494
Регистрация: 15.11.2014
Сообщений: 6,480
Завершенные тесты: 1
04.04.2016, 01:07 #8
Цитата Сообщение от illya05 Посмотреть сообщение
Может я не так выразился, но мне нужно примерно это:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const size_t cn = 5;
string command[cn] = {};
 
size_t ci = 0;
for(const auto& word : words(temp)){
    command[ci] = word;
    ++ci;
    if(ci==cn) {
        std::cout <<"массив command["<<cn <<"] слишком маленький,"
            "что бы вместить в себя все токены командной строки\n"
            "операция считывания токенов прервана\n";
        break;
    }
}
1
illya05
139 / 95 / 19
Регистрация: 03.08.2013
Сообщений: 764
04.04.2016, 01:15  [ТС] #9
То, что нужно! Спасибо огромное еще раз!
0
hoggy
6701 / 2883 / 494
Регистрация: 15.11.2014
Сообщений: 6,480
Завершенные тесты: 1
04.04.2016, 01:17 #10
эм... правильнее будет вот так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const size_t cn = 5;
string command[cn] = {};
 
size_t ci = 0;
for(const auto& word : words(temp)){
    if(ci==cn) {
        std::cout <<"массив command["<<cn <<"] слишком маленький,"
            "что бы вместить в себя все токены командной строки\n"
            "операция считывания токенов прервана\n";
        break;
    }
    command[ci] = word;
    ++ci;
}
1
illya05
139 / 95 / 19
Регистрация: 03.08.2013
Сообщений: 764
05.04.2016, 00:20  [ТС] #11
hoggy, Еще один баг нашел если вводить 2 параметра в кавычках
Ввод: copy "D:\test\f" "E:\sda"
Ошибка (путь, код): D:\test\fE:\sda, code = 124, The path in the source or destination or both was invalid.

Добавлено через 21 час 20 минут
Как исправить?
0
hoggy
6701 / 2883 / 494
Регистрация: 15.11.2014
Сообщений: 6,480
Завершенные тесты: 1
06.04.2016, 00:00 #12
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от illya05 Посмотреть сообщение
Как исправить?
вот что бывает, если сразу тесты не использовать.
добавил символ табуляции до кучи.

http://rextester.com/GYZ95399

C++
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
#include <iostream>
#include <cassert>
#include <vector>
#include <string>
 
// ============================================================================
// ============================================================================
 
    /* разбивает строку на токены, с учетом символов пунктуации */ 
 
namespace lex{
 
    namespace tokenizeDetail {
        template<class Ch> struct default_ { const char* delimiters()    { return  " "; } };
        template<> struct default_<wchar_t>{ const wchar_t* delimiters() { return L" "; } };
    } //namespace tokenizeDetail 
 
    #define dDEFAULT \
        tokenizeDetail::default_<typename Str::value_type>::delimiters()
 
    template <class Str, class Callback, class CallbaclD>
    void tokenize(const Str& text, Callback&& callback, CallbaclD&& callbackD, 
        const Str& delimiters = dDEFAULT, bool trimEmpty = true)
    {
        #undef dDEFAULT
        typename Str::size_type pos, lastPos = 0;
        for(;;)
        {
            pos = text.find_first_of(delimiters, lastPos);
            if(pos == Str::npos)
            {
                pos = text.length();
                if(pos != lastPos || !trimEmpty)
                    callback(text.data()+lastPos, pos-lastPos);
                break;
            }
            else if(pos != lastPos || !trimEmpty)
                callback(text.data() + lastPos, pos-lastPos),
                callbackD(text[pos]);
            else
                callbackD(text[pos]);
        
            lastPos = pos + 1;
        }
    }
} // namespace lex
 
// ============================================================================
// ============================================================================
 
void to_new(std::vector<std::string>& dst, const char* p, size_t len)
    { dst.emplace_back(p,len); }
 
void to_new(std::vector<std::string>& dst, const char ch)
    { dst.emplace_back(1,ch); }
 
void to_new(std::vector<std::string>& dst)
    { dst.emplace_back(); }
 
void to_back(std::vector<std::string>& dst, const char q)
{
    if (dst.empty())
        to_new(dst, q);
    else
        dst.back() += q;
}
 
void to_back(std::vector<std::string>& dst, const char* p, size_t len)
{
    if (dst.empty())
        to_new(dst, p, len);
    else
        dst.back() += std::string(p,len);
}
 
 
std::vector<std::string> words(const std::string& line)
{
    std::vector<std::string> result;
    const std::string punctuation = " \t\"";
    enum eSTATE { eSPC, eBEG, eEND, eWRD } st = eSPC;
 
    const auto processWords = [&result, &st](const char* p, size_t len)
    { 
        switch (st)
        {
            case eSPC: to_new (result, p,len);  st = eWRD; break;
            case eEND: to_back(result, p,len);  st = eWRD; break;
            case eBEG: to_back(result, p,len);             break;
            case eWRD: assert(0);                          
        }
    };
    
    const auto processPunctuation = [&result, &st](const char ch)
    { 
        if(ch=='"')
        {
            switch (st)
            {
                case eSPC: st = eBEG; to_new(result); break;
                case eWRD: st = eBEG;                 break;
                case eBEG: st = eEND;                 break;
                case eEND: st = eBEG;                 break;
            }
        }
        else
        {
            switch (st)
            {
                case eWRD: st = eSPC;           break;
                case eEND: st = eSPC;           break;                
                case eBEG: to_back(result, ch); break;
            }
        }
    };
 
    lex::tokenize(line, processWords, processPunctuation, punctuation, true);
    return result;
}
 
 
void test(const std::string& src, const std::vector<std::string>& expected)
{
    std::cout << "---------------------------------------------------------------\n"
        << "'" << src << "'\n";
 
    const auto& tokens = words(src);
 
    const auto s1 = tokens.size();
    const auto s2 = expected.size();
    const auto size = s1 > s2 ? s2 : s1;
 
    if (expected == tokens)
    {
        for(const auto& word: words(src))
            std::cout << "word: '" << word << "'\n";
        return;
    }
 
    for (size_t n = 0; n < size; ++n)
        std::cout
            << "expected ... '" << expected[n] << "'\n"
            << "real ....... '" << tokens[n]   << "'\n\n"
        ;
    if (s1 != s2)
        std::cout << "error: different quantity words\n";
}
 
int main()
{
    std::cout << "Hello, world!\n";
    
    test( "download http://example.com/\"folder name\"/1.txt 1.txt",
        { "download", "http://example.com/folder name/1.txt", "1.txt" }
    );
    test( "download \"http://example.com/folder name/1.txt\" 1.txt",
        { "download", "http://example.com/folder name/1.txt", "1.txt" }
    );
    test( "download \"http://example.com/folder name/1.txt\"\"\" 1.txt",
        { "download", "http://example.com/folder name/1.txt", "1.txt" }
    );
    test( "download \"http://example.com/folder name/1.txt\" \"1.txt\"",
        { "download", "http://example.com/folder name/1.txt", "1.txt" }
    );
    test( "download \t\"http://example.com/folder name/1.txt\" \t\"1.txt\"",
        { "download", "http://example.com/folder name/1.txt", "1.txt" }
    );
    test( "download \t\"http://example.com/folder name/1.txt\" \t\"1.txt\"    ",
        { "download", "http://example.com/folder name/1.txt", "1.txt" }
    );
    test( "   download \t\"http://example.com/folder name/1.txt\" \t\"1.txt\"    ",
        { "download", "http://example.com/folder name/1.txt", "1.txt" }
    );
    test( "  \t download \t\"http://example.com/\"folder name\"/1.txt\" \t\"1.txt\"    ",
        { "download", "http://example.com/folder", "name/1.txt", "1.txt" }
    );
    test( "  \t download \t\"http://example.com/\"\"folder name\"\"/1.txt\" \t\"1.txt\"    ",
        { "download", "http://example.com/folder name/1.txt", "1.txt" }
    );
    test( "download \"http://example.com/folder name/1.txt\" \"1.txt\" \"   ",
        { "download", "http://example.com/folder name/1.txt", "1.txt", "   " }
    );
}
2
illya05
139 / 95 / 19
Регистрация: 03.08.2013
Сообщений: 764
06.04.2016, 00:20  [ТС] #13
Работает! Спасибо еще раз!!

Добавлено через 3 минуты
И как Вам только терпения хватает...
0
06.04.2016, 00:20
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.04.2016, 00:20
Привет! Вот еще темы с ответами:

Быстрый парсинг строки - C++
Всем доброго времени суток... Прошу разъяснить что делаю не так. Получаю строку вида, нужно ее обработать с минимальными задержками, по...

Парсинг строки с пробелами - C++
Вообщем на выходе всего я получаю вот это : Вот сам файл script.csx: script dadada по идеи должно написать:

Парсинг чисел из строки - C++
Подскажите пожалуйста функцию, которая моглабы парсить из строки. Ну что-то на подобии sscanf, только наоборот Чтобы получилось что то...

Парсинг опций командной строки - C++
Всем привет) Пишу приложение при помощи Qt. Хочу внедрить поддержку командной строки, чтобы можно было использовать программу как...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru