C++11 позволяет чрезвычайно легко обрабатывать даже экранированные запятые, используя regex_token_iterator:
std::stringstream ss(sText);
std::string item;
const regex re{"((?:[^\\\\,]|\\\\.)*?)(?:,|$)"};
std::getline(ss, item)
m_vecFields.insert(m_vecFields.end(), sregex_token_iterator(item.begin(), item.end(), re, 1), sregex_token_iterator());
Кстати, если вы просто хотите создать vector<string>
из CSV string
, такого как item
, вы можете просто сделать:
const regex re{"((?:[^\\\\,]|\\\\.)*?)(?:,|$)"};
vector<string> m_vecFields{sregex_token_iterator(item.begin(), item.end(), re, 1), sregex_token_iterator()};
[Живой пример]
Некоторое краткое объяснение regex
, вероятно, в порядке. (?:[^\\\\,]|\\\\.)
соответствует экранированным символам или символам, отличным от ','
. (Подробнее см. здесь: https://stackoverflow.com/a/7902016/2642059) *?
означает, что это не является жадным соответствием, поэтому оно остановится на первом достигнутом ','
. Все это вложено в захват, который выбирается по последнему параметру, от 1
до regex_token_iterator
. Наконец, (?:,|$)
будет соответствовать либо разделителю ','
, либо концу string
.
Чтобы эта стандартная программа чтения CSV игнорировала пустые элементы, регулярное выражение можно изменить так, чтобы оно соответствовало только строкам, содержащим более одного символа.
const regex re{"((?:[^\\\\,]|\\\\.)+?)(?:,|$)"};
Обратите внимание, что '+'
теперь заменило '*'
, указывая на то, что требуется 1 или более совпадающих символов. Это предотвратит сопоставление вашей строки item
, которая заканчивается на ','
. Пример этого можно увидеть здесь: http://ideone.com/W4n44W.
person
Jonathan Mee
schedule
05.03.2015
std::getline
извлекает до тех пор, пока не будет найден разделитель. Но для последнего элемента нет следующего разделителя,
, поэтому ничего не извлекается, и, таким образом, цикл while завершается. - person AquilaRapax   schedule 03.07.2012