Разбор файла в С++

У меня есть строковые данные в следующем формате: "Ronit", "abc" "defgh", "abcdef", "fdfd",

Может кто-нибудь предложить хороший код в С++ для возврата разделенных запятыми токенов, когда запятые не находятся внутри строки?

т.е. он должен вернуться

  • "Ronit"
  • "а" "defgh"
  • "ABCDEF" fdfd "

чтобы быть более понятным

Спасибо всем вам за любезную помощь.

Ниже приведен мой пример файла, который указан как вход,

Первая строка расскажет мне, сколько столбцов у меня есть #

Имя1, Имя2, NAME3, Name4

"user1", "user, user2", "user3" , "userrr

rrr4",

"user1", "user2", "user3" , "нас

Er4",

"User1", "пользователь, 2", "user3" , "user4"

"," user2, "", "", #

Ниже приведен вывод файла csv, пожалуйста, дайте мне код компиляции, чтобы я мог протестировать, еще раз спасибо за вашу любезную помощь.

1st Row, 1) user1, 2) user, user2 3) user3 4) userrrr4

Примечание. rr4 находится в следующей строке.

2nd Row, 1) user1 2) user2 3) user3 4) us er4

note er4 находится в следующей строке.

3-я строка, 1) user1 2) пользователь, 2 3) user3 4) user4

четвертая строка 1) 2) user2 3) 4)

Ответ 1

С++ String Toolkit Library (StrTk) имеет следующее решение вашей проблемы:

#include <iostream>
#include <string>
#include <deque>
#include "strtk.hpp"

int main()
{
   std::deque<std::string> word_list;
   strtk::for_each_line("data.txt",
                        [&word_list](const std::string& line)
                        {
                           const std::string delimiters = "\t\r\n ,,.;:'\""
                                                          "[email protected]#$%^&*_-=+`~/\\"
                                                          "()[]{}<>";
                           strtk::parse(line,delimiters,word_list);
                        });

   std::cout << strtk::join(" ",word_list) << std::endl;

   return 0;
}

Дополнительные примеры можно найти Здесь

Ответ 2

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

Ответ 3

Далее предполагается, что вход поступает из некоторого потока (в конце концов, у вас был токен С++). Если это не так, посмотрите на строковые потоки.

std::string read_quoted_string(std::istream& is)
{
  is >> std::ws;
  std::string garbage;
  std::getline(is,garbage,'"'); // everything up to opening quote
  if(!garbage.empty()) throw format_error("garbage outside of quotes", garbage);
  if(!is.good()) return std::string();

  std::string a_string;
  std::getline(is,a_string,'"'); // the string up to closing quote
  if(!is) return std::string();
  return a_string;
}

std::vector<std::string> split_input(std::istream& is)
{
  std::vector<std::string> result;
  while(is) {
    const std::string& a_string = read_quoted_string(is);
    if(is) {
      result.push_back(a_string);
      is >> std::ws;
      std::string garbage;
      std::getline(is,garbage,','); // next delimiter
      if(!garbage.empty()) throw format_error("garbage outside of quotes", garbage);
    }
  }
  if(!is.eof()) throw format_error("error reading token", a_string);
  return result;
}

Это не самый быстрый, который у вас есть, но это простое и очень вероятное решение достаточно быстро.

Ответ 4

Просто загрузите boost и используйте boost.tokenizer.
Это лучшее решение.

Ответ 5

Это возвращает раздельные жетоны точно так, как вы просили:

using namespace std;
vector<string> splitqc(std::string const& s) {
 vector<string> tokens;
 char last=0;
 unsigned start=0;    
 for (unsigned i=0,n=s.length;i!=n;++i) {
  char c=s[i];
  if (c==',' && last='"') {
    tokens.push_back(s.substr(start,(i-1)-start));
    start=i+1;
  }
  last=s[i];  
 }
 return tokens;
}

Здесь более общий объект (функтор f вызывается с каждым токеном, обратите внимание, что он не будет иметь тесную цитату, что часть вашего разделителя, вам придется добавить это самостоятельно):

template <class Func>
inline void split_noquote(
    const std::string &csv,
    Func f,
    const std::string &delim=","
    )
{
    using namespace std;
    string::size_type pos=0,nextpos;
    string::size_type delim_len=delim.length();
    if (delim_len==0) delim_len=1;
    while((nextpos=csv.find(delim,pos)) != string::npos) {
        if (! f(string(csv,pos,nextpos-pos)) )
            return;
        pos=nextpos+delim_len;
    }
    if (csv.length()!=0)
        f(string(csv,pos,csv.length()-pos));
}

Использование: split_noquote (s, func, "\", ")

Ответ 6

Это не лучший способ, но вы можете использовать функцию strtok.

Ответ 7

Я не думаю, что что-то вроде "abcdef", "fdfd" может быть проанализировано. Это незаконно, для любого языка и для любого формата данных, потому что одна из цитат не завершена. Должно быть "abcdef, fdfd", Учитывая, что все строки правильно завершены, следующая функция даст нужный результат.

std::istream& tokenize_quoted_strings(std::istream& in, 
                              std::string& dest,
                              char delim)
{
  dest.erase();
  char ch = 0;
  bool in_quotes = false;
  while (in)
    {
      if (!in.get(ch)) break;      
      if (!in_quotes && ch == delim) break;
      dest.push_back(ch);
      if (ch == '"') in_quotes = !in_quotes;
    }
  return in;
}

Следующая функция использует tokenize_quoted_strings для разбиения строки на вектор токенов:

typedef std::vector<std::string> StringList;

void tokenize_line(const std::string& line,
           StringList& tokens)
{
  std::istringstream iss(line);
  std::string token;
  tokens.clear();
  while (tokenize_quoted_strings(iss, token, ','))
    tokens.push_back(token);
}

Использование:

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

int main()
{  
  std::fstream in("test.txt", std::ios_base::in);
  std::string line;
  StringList tokens;
  while (getline(in, line))
    {
      tokenize_line(line, tokens);
      size_t sz = tokens.size();
      for (size_t i=0; i<sz; ++i)
    std::cout << (i+1) << ") " << tokens[i] << ' ';
      std::cout << '\n';
    }
  return 0;
}

Обратите внимание, что это не имеет никакого отношения к экранированным кавычкам стиля C.