将宽字符串提振日期 [英] Convert wide character strings to boost dates

查看:137
本文介绍了将宽字符串提振日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要转换存储为宽字符串到升压日期数百万日期

I need to convert several million dates stored as wide strings into boost dates

以下code工作。然而,它产生一个可怕的编译器警告似乎并没有有效的。

The following code works. However, it generates a horrible compiler warning and does not seem efficient.

有没有更好的办法?

#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 ++标准库的区域设置的,这是的的集合。一个方面是一种服务,它允许运营商的流处理特定选择日期或时间再presentation或其它任何东西。有关diferent事情,按照各自的面处理,所有的选择都在一个区域聚集。


The better way turns out to be to use the standard C++ library locale, which is a collection of facets. A facet is a service which allows the stream operators to handle a particular choice for date or time representation or just about anything else. All the choices about diferent things, each handled by its own facet, are gathered together in a locale.

此溶液向我指出由 litb 谁给了我足够的帮助,我的生产$ C $使用方面C,使得它更简洁和更快。谢谢你。

This solution was pointed out to me by litb who gave me enough help to use facets in my production code, making it terser and faster. Thanks.

有是href=\"http://www.cantrip.org/locale.html\" rel=\"nofollow\">的语言环境和侧面由内森·迈尔斯是谁设计方面优秀教程的

There is an excellent tutorial on locales and facets by Nathan Myers who designed facets. He has a light style which makes his tutorial easy to read, though this is advanced stuff and your brain may hurt after the first read through - mine did. I suggest you go there now. For anyone who just wants the practicalities of converting wide character strings to boost dates, the rest of this post describes the minimum necessary to make it work.

litb首次提供了以下简单的解决方案,消除编译器警告。 (之前,我得到周围接受它的溶液编辑。)这看起来像它做同样的事情,逐个转换宽字符,但它避免了温度串绕碴,因此更清晰,我想。我真的很喜欢的编译器警告已经一去不复返了。

litb first offered the following simple solution that removes the compiler warning. ( The solution was edited before I got around to accepting it. ) This looks like it does the same thing, converting wide characters one by one, but it avoids mucking around with temp strings and therefore is much clearer, I think. I really like that the compiler warning is gone.

#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继续使用面,这是我以前从未听到过的建议。他们似乎做的工作,生产循环中极其简洁code,在那里的区域设置了一个序幕的成本。


litb went on to suggest using "facets", which I had never heard of before. They seem to do the job, producing incredibly terse code inside the loop, at the cost of a prologue where the locale is set up.

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;

本,它的出现,也更有效的:

This, it turns out, is also more efficient:

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;

产生下面的输出:

Produces the following output:


1st method: 2.453
2nd method: 2.422
3rd method: 1.968

OK,这是目前在生产code并通过回归测试。它看起来是这样的:

OK, this is now in the production code and passing regression tests. It looks like this:

  //  .. 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

我对这个最后一个问题。添加面的区域似乎需要语言环境的拷贝构造函数的两次调用

I have one final question about this. Adding the facet to the locale seems to require two invocations of the locale copy constructor

    // add facet to locale
greek_locale = locale( greek_locale, &greek_date_facet );

为什么会出现没有一个附加(面*)的方法? (_Addfac()是复杂的,没有证件和德precated)

Why is there not an add( facet* ) method? ( _Addfac() is complex, undocumented and deprecated )

推荐答案

efotinis发现使用的好办法 from_stream

efotinis found a good way using from_stream .


我已经研究过的 DATE_TIME 手册,发现它支持方面:

I've looked into the manual of date_time and found it supports facets:

#include <boost/date_time/gregorian/gregorian.hpp>
#include <iostream>
#include <sstream>
#include <locale>

int main() {
    using namespace boost::gregorian;

    std::wstringstream ss;
    wdate_input_facet * fac = new wdate_input_facet(L"%Y-%m-%d");
    ss.imbue(std::locale(std::locale::classic(), fac));

    date d;
    ss << L"2004-01-01 2005-01-01 2006-06-06";
    while(ss >> d) {
        std::cout << d << std::endl;
    }
}

您也可以去这一点。


我抬头一看日期方面是如何工作的:

I've looked up how date facets work:


  • 的boost :: date_time的:: date_input_facet 模板实现了一个方面。

  • 构面都源于的std ::区域::面键,每个人都有一个唯一的ID。

  • 您可以的灌输的一个新的语言环境到一个流,取代旧的语言环境。流的区域将被用于各种解析和转换。

  • 当您使用的形式我发现一个新的的std ::区域,你给它一个现有的语言环境和指针方面。给定的小面将替换在给定的区域设置相同类型的任何现有的小面。 (因此,这将取代使用的任何其他date_input_facet)。

  • 所有方面都与区域设置某种联系,这样就可以使用的std :: has_​​facet&LT;小关节及GT;(some_locale)来检查给定的语言环境是否有一定的定侧面类型。

  • 刻面&GT;(some_locale).some_member ...
  • 您可以通过执行的std :: use_facet&LT使用面从一个区域
  • date_input_facet有一个函数得到的,它可以这样用:

  • The boost::date_time::date_input_facet template implements a facet.
  • Facets are derived from std::locale::facet and every one has an unique id.
  • You can imbue a new locale into a stream, replacing its old locale. The locale of a stream will be used for all sorts of parsing and conversions.
  • When you create a new std::locale using the form i showed, you give it an existing locale, and a pointer to facet. The given facet will replace any existing facet of the same type in the locale given. (so, it would replace any other date_input_facet used).
  • All facets are associated with the locale somehow, so that you can use std::has_facet<Facet>(some_locale) to check whether the given locale has some given facet type.
  • You can use a facet from one locale by doing std::use_facet<Facet>(some_locale).some_member... .
  • date_input_facet has a function get, which can be used like this:

下面基本上是由做运营商的GT;&GT; 通过升压:: date_type:

The below is essentially done by operator>> by boost::date_type :

// assume src is a stream having the wdate_input_facet in its locale. 
// wdate_input_facet is a boost::date_time::date_input_facet<date,wchar_t> typedef.

date d;

// iterate over characters of src
std::istreambuf_iterator<wchar_t> b(src), e;

// use the facet to parse the date
std::use_facet<wdate_input_facet>(src.getloc()).get(b, e, src, d);

这篇关于将宽字符串提振日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆