C++最速マスター その3
- 作者: グレゴリーサティア,ダウグブラウン,Gregory Satir,Doug Brown,望月康司,谷口功
- 出版社/メーカー: オライリー・ジャパン
- 発売日: 2001/11
- メディア: 単行本
- 購入: 9人 クリック: 147回
- この商品を含むブログ (29件) を見る
index
- Char Pointer
- String Function
- wide character / wstring
- atof/atoi/atol
- join/split
- character encoding conversion
- zen2han / han2zen
- kata2hira / hira2kata / latin2kata / latin2kata / kata2latin/ latin2hira / hira2latin
- Regex
- regcomp / regexec / regfree / regerror
Char Pointer
C++の場合string型を使ってしまいがちですが、標準関数がcharにしか対応していない(stringがNG)ことも多くcharの性質を理解しておきます。charは1文字を表す型で配列にすると文字列が表現できます。ポインタにはデータのアドレスが格納、ポインタ変数には配列の先頭アドレスが格納されるのでインクリメントしてアドレスの中身であるデータを取得します。char配列はint配列と性質が異なります。例えばint *pp = {1,2,3,4,5}; はコンパイルエラーになりますが、char *stp = "abcedf";は格納できます。char型だけ特別と考えると良いと思います。
※RiSKさんからの指摘でint配列の繰り返し文が参照してはいけない添字にアクセスしているという事が分かり、while文を修正しました。(2012/5/1)#include <iostream> using namespace std; int main() { int p[] = {1,2,3,4,5}; int *pp = &p[0]; // 下はerrorになる // int *pp = {1,2,3,4,5}; int psize = sizeof( p ) / sizeof( p[0] ); int n = 0; // int配列の中身を一つずつ出力 cout << "int array" << endl; while( n < psize ) { cout << p[n] << endl; n++; } /* while( p[n] != '\0' ) { cout << p[n] << endl; ++n; } */ putchar( '\n' ); // int配列の中身をポインタで出力 cout << "int pointer" << endl; n = 0; while( n < psize ) { cout << pp << endl; cout << *pp << endl; ++pp; ++n; } /* while( *pp != '\0' ) { cout << pp << endl; cout << *pp << endl; ++pp; } */ putchar( '\n' ); // 文字配列をポインタで参照し一つずつ出力 cout << "char pointer" << endl; while( *stp != '\0' ) { cout << &stp << endl; cout << *stp << endl; ++stp; } }実行結果
int array 1 2 3 4 5 int pointer 0x7fffb08963e0 1 0x7fffb08963e4 2 0x7fffb08963e8 3 0x7fffb08963ec 4 0x7fffb08963f0 5 char array a b c e d f char pointer 0x7fffb08963c8 a 0x7fffb08963c8 b 0x7fffb08963c8 c 0x7fffb08963c8 e 0x7fffb08963c8 d 0x7fffb08963c8 f
String Function
wide character / wstring
wstringとはUNICODE用の文字列格納型です。文字を宣言する時にLのリテラルを指定することと、単純なcoutでは文字化けするのでlocale設定とwcoutを使うようにします。
#include <iostream> #include <string> #include <locale> using namespace std; int main() { locale::global(locale("ja_JP.UTF-8")); wstring wstr = L"あいうえお"; wcout << wstr << endl; return 0; }実行結果
あいうえおatof/atoi/atol
char型文字列を変換する関数です。atof:double型へ、atoi:int型へ、atol:long型へ変換します。
#include <iostream> using namespace std; int main() { char str_i[] = "12345"; char str_d[] = "123.45a"; double d = atof( str_d ); int i = atoi( str_i ); long l = atol( str_d ); cout << i << endl; cout << d << endl; cout << l << endl; return 0; }実行結果
12345 123.45 123join/split
C++の文字列/配列処理でjoin/splitが残念ながら用意されていないので自前で作成します。vectorとstringのappendを使ってjoin、stringstreamとgetlineを利用してvectorにpush_backさせるsplitを簡単に書いてみました。
#include <iostream> #include <string> #include <sstream> #include <vector> using namespace std; string join( vector<string> &vect, const string &delimiter ) { vector<string>::iterator it = vect.begin(); string result; for( ; it != vect.end(); it++ ) { result.append( *it ); if( it + 1 != vect.end() ) { result.append( delimiter ); } } return result; } vector<string> split( const string &str, const char delimiter ) { vector<string> result; stringstream ss( str ); string item; while( getline( ss, item, delimiter ) ) { result.push_back( item ); } return result; } template <typename T> void show_vector( vector<T> &vect ) { vector<T>::iterator it = vect.begin(); cout << "vector values" << endl; for( ; it != vect.end(); it++ ) { cout << *it << endl; } } int main() { vector<string> v; v.push_back( "a" ); v.push_back( "b" ); v.push_back( "c" ); string r = join( v, "," ); cout << "join result = " + r << endl; vector<string> vr = split( r, ',' ); show_vector( vr ); return 0; }実行結果
join result = a,b,c vector values a b ccharacter encoding conversion
C++で文字コード変換をするにはライブラリを用います。libiconvまたはicuを用いるのが一般的なようです。icuのUnicodeStringオブジェクトを介して文字コードの変換を行います。以下の例ではutf-8の文字列をeuc-jpに変換してファイル保存します。まずはicuのライブラリが必要になりますが、以下ではcentosでのパッケージを載せています。またcompile時にicuを使うオプションを指定しないとエラーが出るので注意が必要です。
$ sudo yum install icu libicu libicu-devel -y$ g++ `icu-config --cppflags --ldflags` encoding.cpp#include <string> #include <fstream> #include <unicode/unistr.h> using namespace std; int main() { // utf-8文字列をファイルから読み込み ifstream ifs( "utf8.txt" ); string str; ifs >> str; // Unicodeオブジェクト設定 UnicodeString src( str.c_str(), "utf8" ); char *res = new char[100]; //変換 src.extract(0, src.length(), res, "euc-jp" ); // euc-jpとして保存 ofstream ofs; ofs.open( "euc-jp.txt" ); ofs << res << endl; ofs.close(); return 0; }$ nkf -g utf8.txt UTF-8 $ nkf -g euc-jp.txt EUC-JPzen2han / han2zen
ICU 49.1.1: Transliterator Class Reference
icuライブラリを使って全角<=>半角の変換処理を行います。#include "unicode/translit.h"設定しTransliteratorクラスを使います。Transliteratorクラスに対して変換方法とUnicodeString文字列を渡すだけで変換してくれます。#include "unicode/translit.h" #include <iostream> using namespace std; // 変換内部処理 string ConvertString( UnicodeString str, const UnicodeString convert_type ) { UErrorCode status = U_ZERO_ERROR; Transliterator *myTrans = myTrans->createInstance( convert_type, UTRANS_FORWARD, status ); myTrans->transliterate(str); char* result = new char[ str.length() + 1 ]; str.extract( 0, str.length(), result, "utf8" ); return result; } // 全角 -> 半角IF string zen2han( const UnicodeString str ) { return ConvertString( str, "Fullwidth-Halfwidth" ); } // 半角-> 全角IF string han2zen( const UnicodeString str ) { return ConvertString( str, "Halfwidth-Fullwidth" ); } int main() { cout << zen2han( "アイウエオ" ) << endl; cout << han2zen( "アイウエオ" ) << endl; return 0; }実行結果
アイウエオ アイウエオkata2hira / hira2kata / latin2kata / latin2kata / kata2latin/ latin2hira / hira2latin
icuライブラリでzen2han,han2zenと同じ方法でカタカナ<=>ひらがな、ローマ字<=>カタカナ、ローマ字 <=> ひらがなの変換もできます。
#include "unicode/translit.h" #include <iostream> using namespace std; // 変換内部処理 string ConvertString( UnicodeString str, const UnicodeString convert_type ) { UErrorCode status = U_ZERO_ERROR; Transliterator *myTrans = myTrans->createInstance( convert_type, UTRANS_FORWARD, status ); myTrans->transliterate(str); char* result = new char[ str.length() + 1 ]; str.extract( 0, str.length(), result, "utf8" ); return result; } // 全角 -> 半角IF string zen2han( const UnicodeString str ) { return ConvertString( str, "Fullwidth-Halfwidth" ); } // 半角-> 全角IF string han2zen( const UnicodeString str ) { return ConvertString( str, "Halfwidth-Fullwidth" ); } // カタカナ->ひらがな string kata2hira( const UnicodeString str ) { return ConvertString( str, "Katakana-Hiragana" ); } // ひらがな->カタカナ string hira2kata( const UnicodeString str ) { return ConvertString( str, "Hiragana-Katakana" ); } // ローマ字->カタカナ string latin2kata( const UnicodeString str ) { return ConvertString( str, "Latin-Katakana" ); } // カタカナ->ローマ字 string kata2latin( const UnicodeString str ) { return ConvertString( str, "Katakana-Latin" ); } // ローマ字->ひらがな string latin2hira( const UnicodeString str ) { return ConvertString( str, "Latin-Hiragana" ); } // ローマ字->ひらがな string hira2latin( const UnicodeString str ) { return ConvertString( str, "Hiragana-Latin" ); } int main() { cout << zen2han( "アイウエオ" ) << endl; cout << han2zen( "アイウエオ" ) << endl; cout << kata2hira( "アイウエオ" ) << endl; cout << hira2kata( "あいうえお" ) << endl; cout << latin2kata( "aiueo" ) << endl; cout << kata2latin( "アイウエオ" ) << endl; cout << latin2hira( "aiueo" ) << endl; cout << hira2latin( "あいうえお" ) << endl; return 0; }実行結果
アイウエオ アイウエオ あいうえお アイウエオ アイウエオ aiueo あいうえお aiueo
Regex
regcomp / regexec / regfree / regerror
On-line Manual of "regcomp"
boostライブラリを使うとregexが簡単に実装できますが、regexを入れるのは面倒なのでできるかぎり標準関数で使いたいです。C++というよりはCの記述ですが以下のように実装可能です。regcomp : 正規表現のコンパイル、regexec : 正規表現検索、regfree:正規表現の記憶域をfreeにする、regerror:エラーコードのメッセージを人が読めるように変形。#include <regex.h> #include <iostream> using namespace std; void print_match( char *str, int start, int end ) { char tmp[10]; str += start; end -= start; strncpy( tmp, str, end ); tmp[end] = '\0'; cout << tmp << endl; } int main() { //正規表現 char *regex = "(reg)no(test)"; //検索文字列 char *str = "koreha regnotest desu"; //コンパイルする正規表現文字列 regex_t regext; //マッチ件数 regmatch_t match[3]; //コンパイル if( regcomp( ®ext, regex, REG_EXTENDED | REG_NEWLINE ) ) { cout << "regex compile failed" << endl; return 1; } //実行 if( regexec( ®ext, str, 3, match, 0 ) ) { cout << "Not Found" << endl; return 1; } //出力 print_match( str, match[0].rm_so, match[0].rm_eo ); print_match( str, match[1].rm_so, match[1].rm_eo ); print_match( str, match[2].rm_so, match[2].rm_eo ); //解放 regfree( ®ext ); return 0; }実行結果
regnotest reg test