Парсинг файла в C++

Theorically Вы можете сделать это с помощью stream_set_blocking (), но похожи существуют некоторые ошибки PHP, управляющие STDIN.

Взгляд: http://bugs.php.net/bug.php?id=34972 http://bugs.php.net/bug.php?id=36030

Попытка самостоятельно:

echo "Enter Password: ";
$stdin = fopen('php://stdin','r');
// Trying to disable stream blocking
stream_set_blocking($stdin, FALSE) or die ('Failed to disable stdin blocking');
// Trying to set stream timeout to 1sec
stream_set_timeout ($stdin, 1) or die ('Failed to enable stdin timeout');

14
задан 18 September 2009 в 12:01
поделиться

6 ответов

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

1
ответ дан 1 December 2019 в 13:33
поделиться

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

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

Это не самое быстрое из возможных решений, но это простое и, скорее всего, достаточно быстрое решение.

1
ответ дан 1 December 2019 в 13:33
поделиться

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

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, "\", ")

0
ответ дан 1 December 2019 в 13:33
поделиться

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

-1
ответ дан 1 December 2019 в 13:33
поделиться

Я не думаю, что что-то вроде "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.

-1
ответ дан 1 December 2019 в 13:33
поделиться

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

1
ответ дан 1 December 2019 в 13:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: