Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
illya05
139 / 95 / 47
Регистрация: 03.08.2013
Сообщений: 765
#1

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

03.04.2016, 22:42. Просмотров 625. Ответов 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++):

Добавление разделения строки по пробелам в код
#include &quot;stdafx.h&quot; #include &lt;iostream&gt; #include &lt;clocale&gt; #include...

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

Разделить строку по пробелам и записать полученные части в массив
Здравствуйте. Подскажите, есть ли способ разделить строку по пробелам и...

Парсинг строки
Добрый день,подскажите, почему и как исправить у меня commands.c_str() -...

Парсинг строки С++
Ребят,нигде не нашел ничего дельного,прошу,чтобы натолкнули на мысль или...

парсинг строки
Добрый день. Стоит задача - &quot;найти производную многочлена. Многочлен может быть...

12
hoggy
Заблокирован
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 / 47
Регистрация: 03.08.2013
Сообщений: 765
03.04.2016, 23:33  [ТС] #3
hoggy, Спасибо, но как в командной строке весь путь должен быть в кавычках, а не только часть с пробелом:
Код
download "http://example.com/folder name/1.txt" 1.txt
1
hoggy
Заблокирован
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 / 47
Регистрация: 03.08.2013
Сообщений: 765
04.04.2016, 00:48  [ТС] #5
hoggy, Огромное спасибо! Всего наилучшего Вам!

Добавлено через 4 минуты
hoggy, последний вопрос, если можно. Как в этот for добавить условие (ci < cn)?
0
hoggy
Заблокирован
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 / 47
Регистрация: 03.08.2013
Сообщений: 765
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
Заблокирован
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 / 47
Регистрация: 03.08.2013
Сообщений: 765
04.04.2016, 01:15  [ТС] #9
То, что нужно! Спасибо огромное еще раз!
0
hoggy
Заблокирован
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 / 47
Регистрация: 03.08.2013
Сообщений: 765
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
Заблокирован
06.04.2016, 00:00 #12
Лучший ответ Сообщение было отмечено illya05 как решение

Решение

Цитата Сообщение от 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 / 47
Регистрация: 03.08.2013
Сообщений: 765
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
Привет! Вот еще темы с решениями:

Парсинг строки
Доброе время суток! столкнулся с такой проблемой что странно отрекаются...

Парсинг строки
Добрый день. Помогите с решением следующей задачи. На вход идет строка из 0 и...

Парсинг строки с сайта
привет всем есть сайт и надо с сайта спарсить строчку &lt;p...

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


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

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

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