Извлечение определенной c вещи из строки - PullRequest
0 голосов
/ 05 августа 2020

У меня есть строка в формате <a,b>, которая представляет край в ориентированном графе (a - источник, а b - цель). a и b также сами являются строками (например, a может быть "Square", а b равно "Circle").

Мне нужно создать функцию, которая извлекает a , и еще одна функция, которая извлекает b. Таким образом, подпись будет:

string getSource(String edge); //will return b
string getTarget(String edge); //will return a

Я использую библиотеку std::string для представления этих строк.

Я знаю, что мне нужно найти способ найти разделитель ',' их в середине строки и избавьтесь от '<' и '>'. Но я не смог найти в std::string функцию, которая поможет мне в этом.

Как бы вы, go, сделали это?

Ответы [ 3 ]

1 голос
/ 05 августа 2020

Кажется, это хороший вариант использования регулярного выражения:

std::regex sd {R"(<(.*),(.*)>)"};

, а затем ваши функции могут быть записаны как:

std::string getSource(std::string const & edge) {
  std::smatch m;
  std::regex_match(edge, m, sd);
  return m[1].str();
}

, а в getTarget вы вернете m[2].str();.

0 голосов
/ 05 августа 2020

Звучит так, будто он принадлежит классу, конструктор которого принимает этот std::string аргумент и анализирует его.

class edge {
public:
    edge(const std::string& str);
    std::string source() const { return src; }
    std::string target() const { return tgt; }
private:
    std::string src;
    std::string tgt;
};

edge::edge(const std::string& str) {
    auto comma = std::find(std::begin(str), std::end(str), ',');
    if (str.length() < 3 || comma == std::end(str) || str.front() != '<' || str.back() != '>')
        throw std::runtime_error("bad input");
    src = std::string(std::next(std::begin(str)), comma);
    tgt = std::string(std::next(comma), std::prev(std::end(str)));
}

Я бы не стал использовать регулярное выражение для такого простого анализа. Регулярные выражения дороги и сильно переоценены.

0 голосов
/ 05 августа 2020

Если вы точно знаете, что строка имеет правильный формат, это просто вопрос использования std::find для поиска интересующих символов и последующего построения новой строки из этих итераторов. Например:

std::string getSource(std::string const & edge) {
    return {
        std::next(std::find(std::begin(edge), std::end(edge), '<')),
        std::find(std::begin(edge), std::end(edge), ',')
    };
}

std::string getTarget(std::string const & edge) {
    return {
        std::next(std::find(std::begin(edge), std::end(edge), ',')),
        std::find(std::begin(edge), std::end(edge), '>')
    };
}

Если строки имеют неправильный формат, то эти функции могут проявлять неопределенное поведение. Это можно тривиально исправить с помощью вспомогательной функции:

template <typename T>
std::string checkedRangeToString(T begin, T end) {
    if (begin >= end) {
        // Bad format... throw an exception or return an empty string?
        return "";
    }

    return {begin, end};
}

std::string getSource(std::string const & edge) {
    return checkedRangeToString(
        std::next(std::find(std::begin(edge), std::end(edge), '<')),
        std::find(std::begin(edge), std::end(edge), ',')
    );
}

std::string getTarget(std::string const & edge) {
    return checkedRangeToString(
        std::next(std::find(std::begin(edge), std::end(edge), ',')),
        std::find(std::begin(edge), std::end(edge), '>')
    );
}
...