C++でURLエンコード

C++でツイッタークライアントなぞ作ろうと思ったはいいものの、いざ始めてみると分からないことが多すぎて何をするにも時間が掛かって仕方がない…

そんな僕の無知と実力の無さを物語るつまづき第一弾!!

HTTPリクエストってURLエンコーディングしないといけないの?

なんて事もちゃんと理解してなかったので自戒を込めてURLエンコーダを書きました。

作ったものはなんてこないタダのUTF-8からURLエンコードへの変換関数です。

でも、あれこれと調べるのに無駄に時間が掛かかって結局半日がかりの作業に…

特に時間が掛かったのは文字コード周りの確認とRFCの解読作業。

もう全部UTF-8で統一しちゃえよ、Shift-JISなんて消えて無くなればいいのに(泣)

ついでにC++らしく書くべくstringクラス(本当はクラスじゃないらしいけど)をちょっくらかじったり…

結局多数の文字コードに対応するのは諦め、取り敢えず入力をUTF-8と仮定して作りました。

#include <iostream>
#include <sstream>
#include <string>

std::string percentEnc(std::string str){
	const int NUM_BEGIN_UTF8 = 48;
	const int CAPITAL_BEGIN_UTF8 = 65;
	const int LOWER_BEGIN_UTF8 = 97;

	int charCode=-1;
	std::string encoded;
	std::stringstream out;

	//for文で1byteずつストリームに入れていく
	for(int i=0;str[i]!=0;i++){
		//文字列中の1byte分のデータを整数値として代入
		charCode = (int)(unsigned char)str[i];

		//エンコードする必要の無い文字の判定
		if((NUM_BEGIN_UTF8 <= charCode && charCode <= NUM_BEGIN_UTF8 + 9)
			 || (CAPITAL_BEGIN_UTF8 <= charCode && charCode <= CAPITAL_BEGIN_UTF8 + 25)
			 || (LOWER_BEGIN_UTF8 <= charCode && charCode <= LOWER_BEGIN_UTF8 + 25)
			 || str[i] == '.' || str[i] == '_' || str[i] == '-' || str[i] == '~')
		{
			//エンコードの必要が無い文字はそのままストリームに入れる
			out<<str[i];
		}else{
			//エンコードする場合は%記号と文字コードの16進数表示をストリームに入れる
			out << '%' << std::hex << std::uppercase <<charCode;
		}
	}
	//ストリームの文字列をstringのインスタンスに代入しreturn
	encoded = out.str();
	return encoded;
}

int main(void){
	std::cout<<percentEnc("パーセントエンコーディング")<<std::endl;
	return 0;
}

このコードでは入力された文字列データをfor文で1文字分ずつ文字コード識別し、%xxの形式にする必要がある場合は文字コードを16進表示にしたものを%に続けて、そうでない場合は文字データをそのまま、stringstreamのインスタンスに出力(?)して、URLエンコードの文字列を作っています。

streamを使うと入れた(出力した)ものを勝手に繋げていってくれるので楽でいいですね。最初はstringのインスタンスに+=演算子で足しこんで行こうかと思ったのですが、文字コードの16進表示を得るのにstringstreamを使っているのにstringで文字列を作るのは無駄が多い気がしたので止めました。

あと、C++でCのprintfのように出力フォーマットを指定するには

“<< フォーマット指定子 << データ”

のようにすればいいのですね…初めて知りました(´・ω・`)

冒頭ではUTF-8専用と書きましたが、関数の最初で定義してある定数を変更すれば他の文字コードセットでにも対応出来るはず…です。多分…きっと…恐らく……

これで、取り敢えずURLエンコードは出来るようになったのでツイッタークライアント作成の道も一歩前進ですかね? まぁぼちぼちやっていきます。

それでは ノシ~

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です