2013-11-06 2 views
2

У меня есть c_str, который содержит [51,53]. Я хочу разбить эти пары на два целых числа. Они находятся в c_str, потому что я читаю их из входного файла.Как разобрать c_str

Должен быть простой способ их разбора. Я думал об использовании функции .at :. Но я уверен, что я сделал это сложно. Кроме того, она не работает, так как он выводит:

pair: 0x7ffffcfc2998 
pair: 0x7ffffcfc2998 
etc 
string pairstring = buffertm.c_str(); 
stringstream pair1, pair2; 
int pairint1, pairint2; 
pair1 << pairstring.at(1) << pairstring.at(2); 
cout << "pair: " << pair1; 
pair1 >> pairint1; 
pair2 << pairstring.at(4) << pairstring.at(5); 
//cout << "pair: " << pair2; 
pair2 >> pairint2; 

Есть лучшие способы сделать это?

+4

«они находятся в c_str» Это не делает Если вы назначаете std :: string другой std :: string, вызов c_str бесполезен. – SirDarius

+0

Обратите внимание, что 'c_str()' является просто функцией-членом 'std :: string', которая возвращает char *, который содержит символы строки. – JBL

+0

Да, вы правы. Поскольку я читал их из файла, у меня уже была эта строка там string buffertm; tmfile >> buffertm; string pairstring = buffertm.c_str(); – dorien

ответ

5

Что-то вроде этого:

char c1, c2, c3; 
int first, second; 

std::istringstream iss(str); 

if (iss >> c1 >> first >> c2 >> second >> c3 
    && c1 == '[' && c2 == ',' && c3 == ']') 
{ 
    // success 
} 

Вы можете бросить в дополнительной проверке, чтобы увидеть, если есть больше символов после закрывающей скобки:

if ((iss >> std::ws).peek() != EOF) { 
    //^^^^^^^^^^^^^^ 
    // eats whitespace chars and returns reference to iss 
    /* there are redundant charactes */ 
} 
+0

Отличное надежное решение. Только * не должно быть до экзамена. – dorien

+0

@dorien спасибо, была опечатка – jrok

1

Если вы достаточно уверены в формате строки, вы можете поместить все это в stringstream, а затем использовать оператор извлечения; например .:

stringstream strm(pairstring);  
int pairint1 = 0, pairint2 = 0; 
char c = 0; 

strm >> c >> pairint1 >> c >> pairint2 >> c; 

На самом деле вы хотите проверить некоторые ошибки там тоже, но мы надеемся, что это достаточно идей, чтобы вы начали.

4

Попробуйте это с помощью C++ 11 std::stoi:

char c_str[] = "[51,53]"; 
std::string s(c_str); 
int num1 = std::stoi(s.substr(1, 2)); 
int num2 = std::stoi(s.substr(4, 2)); 

Если вы знаете, что номера будут находиться за пределами диапазона 10-99 затем использовать это вместо того, чтобы:

char c_str[] = "[5156789,5]"; 
std::string s(c_str); 
s.assign(s.substr(1, s.size() - 2));   // Trim away '[' and ']' 
std::string::size_type middle = s.find(','); // Find position of ',' 
int num1 = std::stoi(s.substr(0, middle)); 
int num2 = std::stoi(s.substr(middle + 1, s.size() - (middle + 1))); 

Функция stoi выбросит std::invalid_argument если номер не может быть проанализирован.

Edit:

Для более rubust решение, которое будет только синтаксический анализ BASE-10 номера, вы должны использовать что-то вроде этого:

char c_str[] = "[51,0324]"; 

int num1, num2; 
try { 
    std::string s(c_str); 
    s.assign(s.substr(1, s.size() - 2)); 
    std::string::size_type middle = s.find(','); 

    std::unique_ptr<std::size_t> pos{new std::size_t}; 

    std::string numText1 = s.substr(0, middle); 
    num1 = std::stoi(numText1, pos.get()); // Try parsing first number. 
    if (*pos < numText1.size()) { 
     throw std::invalid_argument{{numText1.at(*pos)}}; 
    } 

    std::string numText2 = s.substr(middle + 1, s.size() - (middle + 1)); 
    num2 = std::stoi(numText2, pos.get()); // Try parsing second number. 
    if (*pos < numText2.size()) { 
     throw std::invalid_argument{{numText2.at(*pos)}}; 
    } 
} catch (const std::invalid_argument& e) { 
    std::cerr << "Could not parse number" << std::endl; 
    std::exit(EXIT_FAILURE); 
} 

Это отбросит std::invalid_argument при попытке разобрать строки как "1337h4x0r" и т.п., в отличие от использования std::istringstream. Se this for more info

+2

Это решение предполагает, что все целые числа будут в интервале [10,99]. Я не уверен, что это достаточно устойчиво. – SirDarius

+0

@SirDarius Отредактировал мой ответ. – Snps

0

Попробуйте разделить вашу строку с помощью strtok функция. Для конвертации используется atoi.

+0

Даже в C это плохая идея: 'strtok' не реентера и не изменяет строку, которую он разбор; и 'atoi' не обнаруживает ошибок. В C++ существуют гораздо лучшие альтернативы. –

3

По ряду причин я рекомендую двухэтапный процесс, а не пытаюсь сделать все это сразу.

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

1) Просто токвизируйте. Если вы знаете, что это начнется с «[», и вы знаете, что будет запятая, и вы знаете, что получите только два числа, найдите строку для «[», затем используйте substr(), чтобы получить все между ним и запятой. Это один знак. Затем сделайте что-то подобное от запятой до «]», чтобы получить второй токен.

2) Как только у вас есть две строки, относительно просто преобразовать их в целые числа, и есть несколько способов сделать это.

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

0

У меня есть c_str, который содержит [51,53]

Нет, c_str() не структура данных, это метод std::basic_string, который возвращает постоянную строку C с данными, эквивалентных тем, которые хранятся в std::string.

string pairstring = buffertm.c_str(); является громоздким, просто сделайте string pairstring = buffertm; или используйте напрямую buffertm.

Во-вторых, вы используете ваш stringstream в неправильном направлении, вы должны использовать istringstream (здесь вы используете его как ostringstream:.

int i, j; 
istringstream iss(buffertm); 
iss.get() 
iss >> i; 
iss.get() 
iss >> j; 
iss.get(). 
Смежные вопросы