Изменение и извлечение строк C++ на основе разделителей

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

У меня есть входной файл, который я втягиваю, и мне нужно поместить его в одну строковую переменную. Проблема в том, что мне нужно разделить эту строку на разные части. Будет 3 строки и 1 int. Они разделены знаком «:».

Я знаю, что могу найти позицию первого ":" с помощью find (), но я действительно не знаю, как продвигаться по строке для каждой вещи и помещать ее в ее собственную строку / int.

Фактический ввод из файла выглядит примерно так:

A:PEP:909:Inventory Item

A будет командой, которую я должен выполнить ... так что это будет строка. PEP - это ключ, он должен быть строкой. 909 - это int.

и последняя строка.

Так что, как мне кажется, я хочу иметь 3 строковых var и 1 int и поместить все эти вещи в соответствующие переменные.

Поэтому я думаю, что в конечном итоге мне захочется преобразовать эту строку C++ в строку C, чтобы я мог использовать atoi для преобразования одного раздела в int.

Спрашивали и отвечали несколько раз: stackoverflow.com/questions/53849/…

Martin York 28.11.2008 04:55

это не совсем то же самое. в этом случае ему нужно что-то из этого преобразовать. простой цикл getline этого не сделает

Johannes Schaub - litb 28.11.2008 05:15

Проверьте еще раз по ссылке Мартина. Я разместил свой код там. Это похоже на трехстрочный цикл while для разделения строк. Затем он может просто использовать atol (stringVector [2] .c_str ()) для получения числа. Или atoi (), если он хочет. Или атолл (). Или atoq ().

Mr.Ree 28.11.2008 06:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
4 612
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Со строками в стиле C вы можете использовать strtok () для этого. Вы также можете использовать sscanf ()

Но поскольку вы имеете дело с C++, вы, вероятно, захотите использовать встроенные функции std :: string. Таким образом, вы можете использовать find (). У Find есть форма, которая принимает второй аргумент, который является смещением для начала поиска. Таким образом, вы можете найти (':'), чтобы найти первый экземпляр, а затем использовать find (':', firstIndex + 1), чтобы найти следующие экземпляры, где firstIndex - это значение, возвращаемое первым вызовом find ().

Удобное решение, которое я нашел, не редкость - это следующий прототип:

string SplitToken(string & body, char separator)

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

«Моя» реализация MFC - CString выглядит следующим образом:

CString SplitStringAt(CString & s, int idx)
{
   CString ret;
   if (idx < 0)
   {
      ret = s;
      s.Empty();
   }
   else
   {
      ret = s.Left(idx);
      s = s.Mid(idx+1);
   }
   return ret;
}

CString SplitToken(CString & s,TCHAR separator)
{
   return SplitStringAt(s, s.Find(separator));
}

Это определенно не самый эффективный метод - основным недостатком является то, что изменяется тело и создается новая (частичная) копия для каждого токена, поэтому не используйте его в критичных для производительности местах!

Однако я нашел эту (и несколько связанных с ней функций) чрезвычайно полезной для простых синтаксических анализаторов.

Взгляните на boost :: tokenizer.

boost.org/doc/libs/1_37_0/libs/tokenizer/tokenizer.htm
call me Steve 28.11.2008 04:17

Лучше всего это сделать с помощью std::getline и std::istringstream, если вы хотите использовать стандартную библиотеку C++:

std::string command;
std::string key;
int         id;
std::string item;

std::string line = "A:PEP:909:Inventory Item";

// for each line: 
std::istringstream stream(line);

std::getline(stream, command, ':');
std::getline(stream, key, ':');
stream >> id;
std::getline(stream, item);

// now, process them

Подумайте о том, чтобы поместить его в собственную структуру:

struct record {
    std::string command;
    std::string key;
    int         id;
    std::string item;

    record(std::string const& line) {
        std::istringstream stream(line);
        stream >> *this;
    }

    friend std::istream& operator>>(std::istream& is, record & r){
        std::getline(is, r.command, ':');
        std::getline(is, r.key, ':');
        stream        >> r.id;
        std::getline(is, r.item);
        return is;
    }
};

Следите за тем, чтобы вы не перешли на следующую строку, когда попали в неверно сформированную запись с> 3 или <3 двоеточиями.

Mr.Ree 28.11.2008 05:03

да, предполагается, что линии правильные. теоретически ключ может также содержать '\ n', который затем будет охватывать следующую строку.

Johannes Schaub - litb 28.11.2008 05:10

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

Johannes Schaub - litb 28.11.2008 05:11

Просто комментарий, оператор >> не нужно объявлять другом. Нет закрытых членов, поэтому это может быть внешняя бесплатная функция.

David Rodríguez - dribeas 28.11.2008 10:48

dribeas, это уже бесплатная функция. но он не может быть вызван напрямую и работает только для поиска koenig (ADT) (см. «Внедрение имени друга»). Мне нравится использовать здесь определение друга, так как оно масштабируется, когда вы делаете участников закрытыми.

Johannes Schaub - litb 28.11.2008 14:39

Обычно я использую что-то вроде этого:

void 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);
    }
}

вы можете использовать это так:

std::vector<std::string> tokens;
split("this:is:a:test", ':', tokens);

токены теперь будут содержать "this", "is", "a" и "test"

просто и не нужно добавлять другую библиотеку. Идеально для меня.

Name 31.01.2009 01:21

+1 мое предпочтительное решение, не возиться с find () и индексами.

Frank 11.02.2009 05:36

Должен полюбоваться отрицательный голос за пост годичной давности, который отлично работает ...

Evan Teran 22.03.2010 19:43

Другие вопросы по теме