Мне нужно преобразовать несколько миллионов дат, хранящихся в виде широких строк, в форсированные датыПреобразование строк с широкими символами для повышения дат
Следующий код работает. Однако он генерирует ужасное предупреждение компилятора и не кажется эффективным.
Есть ли лучший способ?
#include "boost/date_time/gregorian/gregorian.hpp"
using namespace boost::gregorian;
#include <string>
using namespace std;
wstring ws(L"2008/01/01");
string temp(ws.length(), '\0');
copy(ws.begin(), ws.end(), temp.begin());
date d1(from_simple_string(temp));
cout << d1;
Лучший способ оказывается использовать стандартный C++ библиотека локаль, которая представляет собой совокупность граней. Фасет - это услуга, которая позволяет операторам потока обрабатывать определенный выбор для представления даты или времени или просто о чем-либо еще. Все варианты о разных вещах, каждый из которых связан с его собственной гранью, собираются вместе в локали.
Это решение было указано мне litb, который дал мне достаточную помощь для использования граней в моем производственном коде, что сделало его более быстрым и быстрым. Благодарю.
Существует excellent tutorial на местах и грани Nathan Myers, которые разработали гранулы. У него легкий стиль, благодаря которому его учебник легко читается, хотя это продвинутый материал, и ваш мозг может повредить после первого прочтения - мой. Я предлагаю вам пойти туда сейчас. Для тех, кто просто хочет практических преобразований широких струн символов для повышения дат, в остальной части этого сообщения описывается минимальное значение, необходимое для его работы.
Вначале предлагается следующее простое решение, которое удаляет предупреждение компилятора. (Решение было отредактировано до того, как я получил его, чтобы принять его.) Похоже, он делает то же самое, преобразовывая широкие символы один за другим, но он избегает развязывания с помощью temp-строк и, следовательно, гораздо яснее. Мне очень нравится, что предупреждение компилятора пропало.
#include "boost/date_time/gregorian/gregorian.hpp"
using namespace boost::gregorian;
#include <string>
using namespace std;
wstring ws(L"2008/01/01");
date d1(from_simple_string(string(ws.begin(), ws.end()));
cout << d1;
LITB продолжал утверждать, используя «аспекты», которые я никогда не слышал раньше. Они, похоже, выполняют эту работу, производя невероятно краткий код внутри цикла, ценой пролога, где установлен языковой стандарт.
wstring ws(L"2008/01/01");
// construct a locale to collect all the particulars of the 'greek' style
locale greek_locale;
// construct a facet to handle greek dates - wide characters in 2008/Dec/31 format
wdate_input_facet greek_date_facet(L"%Y/%m/%d");
// add facet to locale
greek_locale = locale(greek_locale, &greek_date_facet);
// construct stringstream to use greek locale
std::wstringstream greek_ss;
greek_ss.imbue(greek_locale);
date d2;
greek_ss << ws;
greek_ss >> d2;
cout << d2;
Это, оказывается, также более эффективно:
clock_t start, finish;
double duration;
start = clock();
for(int k = 0; k < 100000; k++) {
string temp(ws.length(), '\0');
copy(ws.begin(), ws.end(), temp.begin());
date d1(from_simple_string(temp));
}
finish = clock();
duration = (double)(finish - start)/CLOCKS_PER_SEC;
cout << "1st method: " << duration << endl;
start = clock();
for(int k = 0; k < 100000; k++) {
date d1(from_simple_string(string(ws.begin(), ws.end())));
}
finish = clock();
duration = (double)(finish - start)/CLOCKS_PER_SEC;
cout << "2nd method: " << duration << endl;
start = clock();
for(int k = 0; k < 100000; k++) {
greek_ss << ws;
greek_ss >> d2;
ss.clear();
}
finish = clock();
duration = (double)(finish - start)/CLOCKS_PER_SEC;
cout << "3rd method: " << duration << endl;
Производит следующий вывод:
1st method: 2.453 2nd method: 2.422 3rd method: 1.968
ОК, теперь это в коде производства и прохождения тестов регрессии , Это выглядит так:
// .. construct greek locale and stringstream
// ... loop over input extracting date strings
// convert range to boost dates
date d1;
greek_ss<< sd1; greek_ss >> d1;
if(greek_ss.fail()) {
// input is garbled
wcout << L"do not understand " << sl << endl;
exit(1);
}
greek_ss.clear();
// finish processing and end loop
У меня есть один последний вопрос об этом. Добавление фасет к местности, кажется, требует двух вызовов локали конструктор копирования
// add facet to locale
greek_locale = locale(greek_locale, &greek_date_facet);
Почему не добавить (* фаска) метод?(_Addfac() является сложным, недокументированным и устаревшим)
для вашего теста, после каждого извлечения вы должны вызвать .clear() в потоке. потому что он мог установить флаги ошибок, что приведет к отмене дальнейших операций чтения/записи. – 2008-11-29 21:02:10
так, лучше делать для (int k = 0; k <100000; k ++) {ss << ws; ss >> d2; ss.clear();/* clear возможно eof flag * /} – 2008-11-29 21:05:15
Уже сделано, спасибо. – ravenspoint 2008-11-29 21:06:24