2014-11-27 3 views
3

У меня есть несколько строк, каждая из которых содержит одно слово и несколько целых чисел (одна строки целой линии):C++ как получить только целые числа от сложной строки

Adam 2 5 1 5 3 4 
John 1 4 2 5 22 7 
Kate 7 3 4 2 1 15 
Bill 2222 2 22 11 111 

Как вы можете видеть, каждое слово/число разделяется пробелом. Теперь я хочу загрузить эти данные в карту, где слово (имя) будет ключевым, а значение будет вектором чисел в строке. У меня уже есть ключевые значения в изолированном временном контейнере stl, поэтому задача состоит в том, чтобы загружать только целые числа из каждой строки в 2D-вектор, а затем объединить эти два в карту. Вопрос в том, есть ли какая-либо функция C++, которая позволит избежать слов и пробелов и получать только целые числа из строки, или мне нужно искать строки char-by-char, как here?

Я нашел только частичное решение, которое не в состоянии получить номер более чем одна цифра:

vector<int> out; 

for (int i = 0; i < line.length(); i++) { 

    if (isdigit(line.at(i))) { 
     stringstream const_char; 
     int intValue; 
     const_char << line.at(i); 
     const_char >> intValue; 
     out.push_back(intValue); 
    } 
} 
+0

Является ли имя всегда первым в очереди? – antonpp

+0

Да в этом примере, но было бы полезно найти решение для любого случая – witcher

ответ

2

Если каждая строка имеет формат «номер номера номера ...», используйте строковый поток и пропустите это слово, прочитав его.

Если текущая строка в line:

vector<int> out; 
istringstream in(line); 
string word; 
in >> word; 
int x = 0; 
while (in >> x) 
{ 
    out.push_back(x); 
} 
+0

Я представил что-то в этом роде, спасибо! – witcher

1

использовать находку() и SUBSTR() из строки класса, чтобы найти имя, если оно всегда на начало строки.

std::string s = "Adam 2 5 1 5 3 4"; 
std::string delimiter = " "; 
s.substr(0, s.find(delimiter)); //To get the name 
s.erase(0, s.find(delimiter)); //To delete the name 
//Repeat the mechanism with a for or a while for the numbers 

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

Если имя может быть где угодно, я не вижу, как проверить его без проверки для каждого символа.

2

split строка на пространствах, так что, кажется, ваш разделителем. Затем проверьте, что каждая подстрока содержит int с strol.

Затем используйте stoi для преобразования целочисленных подстрок в int.

Если никакое преобразование stoi не может быть выполнено (строка не содержит числа), генерируется исключение invalid_argument, поэтому не пытайтесь преобразовать подстроку имени.

#include <iostream> 
#include <vector> 
#include <string> 
#include <sstream> 
#include <cstdlib> 

std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) { 
    std::stringstream ss(s); 
    std::string item; 
    while (std::getline(ss, item, delim)) { 
     elems.push_back(item); 
    } 
    return elems; 
} 


std::vector<std::string> split(const std::string &s, char delim) { 
    std::vector<std::string> elems; 
    split(s, delim, elems); 
    return elems; 
} 

inline bool isInteger(const std::string & s) 
{ 
    if(s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false ; 

    char * p ; 
    strtol(s.c_str(), &p, 10) ; 

    return (*p == 0) ; 
} 


int main() 
{ 
    std::cout << "Hello World" << std::endl; 

    std::string example="Adam 2 5 1 5 3 4"; 

    std::vector<std::string> subStrings; 

    subStrings = split(example, ' '); 

    std::string sItem; 
    for(std::vector<std::string>::iterator it = subStrings.begin(); it != subStrings.end(); ++it) { 
     sItem = *it; 
     if(isInteger(sItem)){ 
      int nItem = std::stoi (sItem); 
      std::cout << nItem << '\n'; 
     } 
    } 

    return 0; 
} 
+0

C++ 11 + для stoi – ldgorman

1

Предполагая, что имя на первом месте, вот функция, которая будет читать строку и добавлять ее к карте.

#include <map> 
#include <vector> 
#include <sstream> 
#include <string> 
#include <algorithm> 

using namespace std; 

typedef std::map<std::string, std::vector<int> > StringMap; 

void AddToMap(StringMap& sMap, const std::string& line) 
{ 
    // copy string to stream and get the name 
    istringstream strm(line); 
    string name; 
    strm >> name; 

    // iterate through the ints and populate the vector 
    StringMap::iterator it = sMap.insert(make_pair(name, std::vector<int>())).first; 
    int num; 
    while (strm >> num) 
     it->second.push_back(num); 
} 

Функция выше добавляет новую запись на карту с первым чтением, и последующие чтениями, заполнит вектор.

Обратите внимание, что функция map::insert возвращает std::pair, где first этой пары является итератором к созданной карте. Поэтому мы просто получаем итератор, а оттуда push_back записи.

Вот тестовая программа:

int main() 
    { 
     vector<std::string> data = { "Adam 2 5 1 5 3 4", "John 1 4 2 5 22 7", 
            "Kate 7 3 4 2 1 15", "Bill 2222 2 22 11 111" }; 
     StringMap vectMap; 

     // Add results to map 
     for_each(data.begin(), data.end(), 
       [&](const std::string& s){AddToMap(vectMap, s); }); 

     // Output the results 
     for_each(vectMap.begin(), vectMap.end(), 
       [](const StringMap::value_type& vt) 
       {cout << vt.first << " "; copy(vt.second.begin(), vt.second.end(), 
        ostream_iterator<int>(cout, " ")); cout << "\n"; }); 
    } 

Живой пример: http://ideone.com/8UlnX2

1

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

#include <iostream> 
#include <string> 
#include <vector> 
#include <map> 
#include <sstream> 
#include <iterator> 

int main() 
{ 
    std::string s("Adam 2 5 1 5 3 4"); 
    std::map<std::string, std::vector<int>> m; 
    std::string key; 
    std::istringstream is(s); 

    if (is >> key) 
    { 
     m[key] = std::vector<int>(std::istream_iterator<int>(is), 
            std::istream_iterator<int>()); 
    } 

    for (const auto &p : m) 
    { 
     std::cout << p.first << ": "; 
     for (int x : p.second) std::cout << x << ' '; 
     std::cout << std::endl; 
    } 

    return 0; 
} 

Выход

Adam: 2 5 1 5 3 4 
Смежные вопросы