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');
Для меня это похоже на разбор CSV-файла (даже если он технически не является файлом) - вы можете взглянуть на этот вопрос и ответ .
Далее предполагается, что ввод поступает из некоторого потока (в конце концов, у вас был токен 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;
}
Это не самое быстрое из возможных решений, но это простое и, скорее всего, достаточно быстрое решение.
Это возвращает разделенные токены точно так, как вы просили:
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, "\", ")
Это не лучший способ, но вы можете использовать функцию strtok .
Я не думаю, что что-то вроде "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.
Просто скачайте boost и используйте boost.tokenizer .
Это лучшее решение.