Как мне прочитать строку char за символом в C ++? - PullRequest
6 голосов
/ 18 января 2020

Мне нужно прочитать строковый символ за символом, чтобы выполнить некоторые действия с ним. Возможно ли это сделать? Обязательно ли конвертировать его в массив символов? Я пытался указать на одиночные символы с string_to_control[i], а затем увеличить i, чтобы двигаться, но это, похоже, не работает. В качестве примера я публикую часть кода для контроля скобок.

bool Class::func(const string& cont){
    const string *p = &cont;
    int k = 0;
    //control for parenthesis
    while (p[k].compare('\0') != 0) {
        if (p[k].compare("(") == 0) { ap++; };
        if (p[k].compare(")") == 0) { ch++; };
        k++;
    };
    //...
};

Строка копируется нормально, но как только я пытаюсь выполнить первое сравнение, выдается исключение.

РЕДАКТИРОВАТЬ: Я добавляю, что я хотел бы иметь разные копии исходной строки продолжение (и двигаться на них, а не на продолжение непосредственно), чтобы манипулировать ими (позже в коде, мне нужно проверить, что определенные слова находятся в нужном месте).

Ответы [ 7 ]

6 голосов
/ 18 января 2020

Самый простой способ перебирать строковый символ за символом - диапазон:

bool Class::func(const string& cont){
    for (char c : cont) {
        if (c == '(') { ap++; }
        if (c == ')') { ch++; }
    }
    //...
};

Синтаксис диапазона для был добавлен в C ++ 11. Если по какой-то причине вы используете старый компилятор, который не поддерживает C ++ 11, вы можете отлично выполнять итерацию по индексу без каких-либо преобразований или копий:

bool Class::func(const string& cont){
    for (size_t i = 0; i < cont.size(); ++i) {
        if (cont[i] == '(') { ap++; }
        if (cont[i] == ')') { ch++; }
    }
    //...
};
4 голосов
/ 18 января 2020
const string *p = &cont;
int k = 0;
while (p[k].compare('\0') != 0)

Обрабатывает p, как если бы это был массив, так как p указывает только на одно значение, ваш код имеет неопределенное поведение, когда k не равен нулю. Я предполагаю, что вы на самом деле хотели написать:

bool Class::func(const string& cont){
    while (cont[k] != '\0') {
        if (cont[k] == '(') { ap++; };
        if (cont[k] == ') { ch++; };
        k++;
    };
};

Более простым способом было бы перебрать std::string с использованием begin() и end() или еще проще просто использовать диапазон для l oop:

bool Class::func(const string& cont){
    for (char ch : cont) {
        if (ch == '(') { ap++; };
        if (ch == ')') { ch++; };
    };
};

Если вы хотите скопировать вашу строку, просто объявите новую строку:

std::string copy = cont;
4 голосов
/ 18 января 2020

Если вы просто хотите сосчитать открывающую и закрывающую скобки, взгляните на это:

bool Class::func(const string& cont) {
    for (const auto c : cont) {
        switch (c) {
            case '(': ++ap; break;
            case ')': ++ch; break;
        }
    }
    // ...
}
2 голосов
/ 18 января 2020

Для подсчета скобок вы можете использовать алгоритм std::count из стандартной библиотеки:

/* const */ auto ap = std::count(cont.begin(), cont.end(), '(');
/* const */ auto ch = std::count(cont.begin(), cont.end(), ')');

Строка будет пройдена дважды.

Для одиночного обхода Вы можете реализовать обобщенную функцию c (требуется C ++ 17):

template<class C, typename... Ts>
auto count(const C& c, const Ts&... values) {
    std::array<typename C::difference_type, sizeof...(Ts)> counts{};
    for (auto& value : c) {
        auto it = counts.begin();
        ((*it++ += (value == values)), ...);
    }
    return counts;
}

и затем написать

/* const */ auto [ap, ch] = count(cont, '(', ')');
2 голосов
/ 18 января 2020

Перегрузка std::string::operator[] допускает выражения, такие как cont[k]. Ваш код обрабатывает p как массив std::string, а не как массив символов, как вы предполагали. Это может быть исправлено с помощью:

const string &p = cont;

, но в этом нет необходимости, поскольку вы уже можете напрямую обращаться к cont.

cont[k] имеет тип char, поэтому вызов std::string::compare() недопустим , Вы можете сравнить char s обычным образом:

cont[k] == '('` 

Вы также должны знать, что перед C ++ 11 конец std::string не ограничен \0, как C string (может быть NUL после строковых данных, но это доверие к удаче). C ++ 11 действительно гарантирует это, но, вероятно, только для «исправления» старого кода, который предполагал, что это так.

Если вы используете std::string::at вместо std::string::operator[], вы получите исключение, если вы превысите пределы. Но вы должны использовать на основе диапазона for, std::string::iterator или std::string::length(), чтобы выполнить итерацию строки до конца.

2 голосов
/ 18 января 2020

Если вы не хотите использовать итераторы, std::string также перегружает operator[], поэтому вы можете получить доступ к символам, как если бы вы использовали char[].

* Например, 1008 * вернет символ с индексом i, затем вы можете использовать ==, чтобы сравнить его с другим символом:

bool Class::func(const string& cont){
    int k = 0;

    while (k < cont.length()) {
        if (cont[k] == '(') { ap++; };
        if (cont[k] == ')') { ch++; };
        k++;
    };
};
0 голосов
/ 18 января 2020

Сначала преобразуйте строку в массив char следующим образом:

bool Class::func(const string& cont){

    char p[cont.size() + 1];
    strcpy(p, cont.c_str());

    int k = 0;
    //control for parenthesis
    while (p[k].compare('\0') != 0) {
        if (p[k].compare("(") == 0) { ap++; };
        if (p[k].compare(")") == 0) { ch++; };
        k++;
    };
    //...
};

Вы можете делать с алгоритмом все, что хотите, что означает, что вы можете избежать преобразования массива:

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>    // std::count

int main()
{
    std::string s = "hi(there),(now))";

    int ap = std::count (s.c_str(), s.c_str()+s.size(), '(');
    int ch = std::count (s.c_str(), s.c_str()+s.size(), ')');

    std::cout << ap <<  "," <<  ch << '\n'; // prints 2,3

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...