Monthly Archives: August 2006

UNICODE, The C++ Way / C++中UNICODE的处理

It’s not as easy as one may think when he comes to deal with UNICODE file with C++ standard library – wchar_t is not enough. 

  • Standard C++(portable way, preferred)

Here below are 2 solutions after searching on the internet.

Solution 1: use codecvt (Upgrading an STL-based application to use Unicode)

 

imbue_null_codecvt.h source code:

#ifndef IMBUE_NULL_CODECVT_H_INCLUDED
#define IMBUE_NULL_CODECVT_H_INCLUDED
 
#include <locale>
using namespace std;    ///< import the c++ name space
using std::codecvt ;
typedef codecvt < wchar_t , char , mbstate_t > NullCodecvtBase ;
 
/**
 * \brief
 * a MACRO to facilitate imbuing a locale with facet NullCodecvt
 *
 */
#define IMBUE_NULL_CODECVT( outputFile ) \
{ \
    (outputFile).imbue( std::locale(locale::classic(), new NullCodecvt )) ; \
}
 

/**
 *  imbue_null_codecvt.h
 *  codecvt facet for std::wofstream to write wchar_t to file in UNICODE
 *
 * This code was originally written by Taka Muraoka and published at
 * http://www.codeproject.com/vcpp/stl/upgradingstlappstounicode.asp
 * and freely available.
 */

class NullCodecvt

    : public NullCodecvtBase
{ 
public:
    typedef wchar_t _E ;
    typedef char _To ;
    typedef mbstate_t _St ;
 
    explicit NullCodecvt( size_t _R=0 ) : NullCodecvtBase(_R) { }
 
protected:
    virtual result do_in( _St& _State ,
                   const _To* _F1 , const _To* _L1 , const _To*& _Mid1 ,
                   _E* F2 , _E* _L2 , _E*& _Mid2
                   ) const
    {
        return noconv ;
    }
    virtual result do_out( _St& _State ,
                   const _E* _F1 , const _E* _L1 , const _E*& _Mid1 ,
                   _To* F2, _E* _L2 , _To*& _Mid2
                   ) const
    {
        return noconv ;
    }
    virtual result do_unshift( _St& _State ,
            _To* _F2 , _To* _L2 , _To*& _Mid2 ) const
    {
        return noconv ;
     }
    virtual size_t do_length( _St& _State , const _To* _F1 ,
           const _To* _L1 , size_t _N2 ) const _THROW0()
    {
        return (_N2 < (size_t)(_L1 – _F1)) ? _N2 : _L1 – _F1 ;
    }
    virtual bool do_always_noconv() const _THROW0()
    {
        return true ;
    }
    virtual int do_max_length() const _THROW0()
    {
        return 2 ;
    }
    virtual int do_encoding() const _THROW0()
    {
        return 2 ;
    }
} ;
 
#endif // IMBUE_NULL_CODECVT_H_INCLUDED
 

 2.Usage, just a macro:

#include "imbue_null_codecvt.h"
#include <fstream>      // std::wfstream
using std::wofstream;
 
 // some code …
wofstream fileLng;
IMBUE_NULL_CODECVT(fileLng);    // prevent from converting UNICODE to MBCS while writing to file
fileLng.open(L"unicode_file", ios::binary | ios::in | ios::out);
if(fileLng.is_open()){…}

Solution 2: Standard C/C++: Multibyte  by PJ Plauger

  •   Windows specific

Paul Dilascia posted a Windows specific solution and explained it in his Q&A column MSDN Magzine Issue August 2004.

 

Calculate 24, A Childhood Game the C++ Way / 算24的C++实现

 This is actually a showcase of the power of the C++ STL library and the BOOST library: Do more while coding less.

 1. Background

It all starts with a favorite game of playing cards since my childhood: Calculating 24. The rule is simple: pick any 4 cards, and try to get a result of 24 from the numbers on the cards,    only with the 4 basic arithmetic operations, namely, addition (+), subtraction (-), multiplication (*)and division (/). Jack (J), Queen (Q), King (K) and Ace (A) represent 11, 12, 13 and 1 respectively, or they all represent 1 in an alternative flavor.

For example, given numbers 3, 3, 4 and 8, we can get such an expression: 3*8*(4-3) = 24.  

A more general mathematic description of this game would be: Given a vector of any length and a set of calculation methods, what is the complete set of calculation results.

2. Algorithm

The computer way to play this game is to 1)get all possible permutations of 4 numbers, 2)calculate all possible arithmetic results for each permutation, and then 3) judge whether 24 is within the result set.  

Step 2 is the core of the algorithm.

Let’s assume a sorted permutation from step 1 is expressed as A1, A2, A3, …, An.

Define F as F (An) = A1 (op) A2 (op) A3,  … An-1 (op) An, where (op) is addition (+), subtraction (-), multiplication (*) and division (/), reverse subtraction or reverse division.

It’s natural that  F (An) =  F (An-1)  (op) An. This is where a recursive function shows its power.

3. Implementation

With the power of STL and BOOST, things can easily be done. The code is so short that it can all be pasted below.

#include <iostream>
#include <vector>       // for vector
#include <set>          // for set
#include <algorithm>    // for for_each(), next_permutation(), prev_permutation()
 
#include <boost/bind.hpp>           // for boost::bind
#include <boost/assign.hpp>         // for vector += assignment
#include <boost/lambda/lambda.hpp>  // for boost::lambda::_1 
#include <boost/lambda/if.hpp>      // for boost::lambda::if_ 
 
using namespace std;
 
template<typename T>
class CCalculate
{
public:
    CCalculate(const vector<T>& v):m_v(v)
    {
    };
 
    set<T> operator() () 
    {
        RecursiveCalculate();
        return m_setNextSum;
    }
 
private:
    vector<T> m_v;
    set<T> m_setPrevSum, m_setNextSum;
 
private:
    void BasicCalculation(T d1, T d2)
    {
        m_setNextSum.insert(d1 - d2);
        m_setNextSum.insert(d1 * d2);
        m_setNextSum.insert(d2 - d1);
        if(0 != d2) m_setNextSum.insert(d1 / d2);
        if(0 != d1) m_setNextSum.insert(d2 / d1);
    }
 
    void RecursiveCalculate(void)
    {
        if(m_v.size() > 2)
        {
            T v_back;
            v_back = m_v.back();
            m_v.pop_back();
 
            RecursiveCalculate();
            swap(m_setPrevSum, m_setNextSum);
            m_setNextSum.clear();
 
            for_each(m_setPrevSum.begin(),
                m_setPrevSum.end(),
                boost::bind(&CCalculate<T>::BasicCalculation, 
                this, 
                _1, 
                v_back));
        }
        else
        {
            m_setNextSum.clear();
            BasicCalculation(m_v.front(), m_v.back() );
        }
    };
};
 
void PrintResult(vector<double> v)
{
    using boost::lambda::_1;
    using boost::lambda::if_;
    using boost::lambda::constant; 
 
    set<double> setFinalVal;
    setFinalVal =  CCalculate<double>(v)();
 
    cout<<"current vector is: [ ";
    for_each( v.begin(), v.end(), cout<<_1<<" " );
    cout<<"]\n";
 
    cout<<"Corresponding Results are:{ ";
    for_each( setFinalVal.begin(), setFinalVal.end(),
        ( cout<<_1<<" ",
          if_((_1 < 24.000001) && (_1 > 23.999999))
            [ cout <<constant("Bingo:<")<< _1<<" found here.> "]
         ) 
            );
 
    cout<<"}\n\n";
}
 
int main()
{
    cout<<"build on "<<__DATE__<<" "<<__TIME__<<endl;
 
    using namespace boost::assign;
    vector<double> vTest;
   
    vTest += 3,3,8,8;
 
    sort(vTest.begin(), vTest.end());
    do{
        PrintResult(vTest);
    } while ( next_permutation( vTest.begin(), vTest.end()));
 
    return 0;
}
 4. Result 

A snapshot of the result is showed below(compiled with VC8.0):