0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaScript で Modified UTF-7 にエンコード&デコード

Posted at

non-ASCII 文字を JSON にエンコードすると1文字6バイトになってデータ量多いよねっていうトークをした時、「じゃあエンコ前に全部 ASCII にすればいいんじゃね?」と考えて調べたら Modified UTF-7 という手頃な文字コードがあったのでエンコーダー作ってみました。

探せば既に誰かやってそうだと思ってましたがざっとググったところ UTF-7 専門エンコーダーが見当たらなかったので自作。
(一番肝心なところが最後の数行にしかないのはあまり突っ込まないでください)

ソース

/** ビットの FIFO */
var BitQueue = function() {};
BitQueue.prototype.value_ = 0;
BitQueue.prototype.length_ = 0;
BitQueue.prototype.getLength = function() { return this.length_; }
BitQueue.prototype.enqueue = function(length, value) {
	this.value_ =
		(this.value_ << length) |
		(((1 << length) - 1) & value);
	this.length_ += length;
};
BitQueue.prototype.dequeue = function(length) {
	var result;
	if(length > 0) {
		this.length_ -= length;
		result =
			(this.value_ >> this.length_) &
			((1 << length) - 1);
		this.value_ &= (1 << this.length_) - 1;
	}
	else {
		result = this.value_;
		this.value_ = this.length_ = 0;
	}

	return result;
};

/** Base64<=>文字列 のエンコーダー */
var Base64 = {
	'CODE_CHAR':
	     'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
	'PADDING': '=',
	'encode': function(str) {
		var bitQueue = new BitQueue();
		var result = '';

		for(var i = 0; i < str.length; ++i) {
			// UTF-16 1文字をエンキュー
			bitQueue.enqueue(16, str.charCodeAt(i));

			// 6bit単位でデキュー
			while(bitQueue.getLength() >= 6) {
				var ch = bitQueue.dequeue(6);

				result += Base64.CODE_CHAR.charAt(ch);
			}
		}

		// 余りには0を詰めて結果に入れる
		if(bitQueue.getLength()) {
			var remain = bitQueue.getLength();
			var ch = bitQueue.dequeue(remain) << (6 - remain);

			result += Base64.CODE_CHAR.charAt(ch);
		}
		// 結果が4n文字になるよう詰め物を入れる
		while(result.length % 4)
			result += Base64.PADDING;

		return result;
	},
	'decode': function(str) {
		var bitQueue = new BitQueue();
		var result = '';

		for(i = 0; i < str.length; ++i) {
			var ch = str.charAt(i);

			// パディングに当たったらやめちゃう
			if(ch === Base64.PADDING)
				break;

			// 文字をコードに変えてエンキュー
			bitQueue.enqueue(6, Base64.CODE_CHAR.indexOf(ch));

			// 16bitたまったらデキュー
			while(bitQueue.getLength() >= 16) {
				var ch = bitQueue.dequeue(16);

				result += String.fromCharCode(ch);
			}
		}

		// エンコの時とは異なり余りは無視しちゃう

		return result;
	}
};

/** ModifiedUTF-7<=>文字列 のエンコーダー */
var MUTF7 = {
	'encode': function(plain_str) {
		return plain_str
			.replace(/&/g, '&-')
			.replace(/[\0- \u007f-\uffff]+/g, function(str) {
				return '&' + Base64.encode(str) + '-';
			});
	},
	'decode': function(utf7_str) {
		return utf7_str
			.replace(/&([A-Za-z0-9\+\/]+=*)-/g, function(str, $1) {
				return Base64.decode($1);
			}).replace(/&-/g, '&');
	}
};

使い方

MUTF7.encode(str) でエンコ、
MUTF7.decode(str) でデコ。
結果は関数の戻り値になります。

Base64 とか BitQueue とかで既にいい感じのライブラリを導入済みであれば適当に書き換えてください。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?