文字列を短くするためにどのタイプのエンコードを使用できますか?


13

私が持っている文字列のエンコードに興味があり、使用できるエンコードの種類があり、英数字のみを含み、文字列を表すために必要な文字数を短くすることが望ましいかどうかに興味があります。

これまで、Base64エンコーディングを使用してこれを行うことを検討しましたが、文字列が長く==なるようで、回避したい場合もあります。例:

テスト名| 120101

になる

dGVzdCBuYW1lfDEyMDEwMQ ==

16文字から24文字になり、英数字以外が含まれます。

私の要件を達成するために使用できる別の種類のエンコーディングを知っていますか?ボーナスは、.NETフレームワークに組み込まれている場合、またはエンコードを実行するサードパーティライブラリが存在する場合にポイントします。


1
ハフマンコーディングのようなロスレス圧縮を使用することはできません!! それらはテキストに理想的に適しています...しかし、受信側では、テキストを取り戻すために行ったこの突然変異について本当に知る必要があります。

6
あなたは、圧縮を記述するエンコードしていない
アンディ・スミス

@アンドリュー-提案はありますか?
阿部ミースラー

回答:


30

Base64の最後の「=」または「==」は、文字数を4の倍数にするためだけにあります。後でいつでも元に戻すことができるため、削除できます。Base64は64個の異なる文字を使用するため、そのように呼ばれることに注意してください。大文字、小文字、数字は62です。したがって、Base64では「/」と「+」も使用されます。

一般的に、任意のバイトシーケンスを英数字にエンコードする場合、1バイトには256個の値があり、英数字は62個しかないため、必然的に何らかの長さ拡張がどこかにあります。それは時々鳩の巣の原理と呼ばれます。エンコーディングスキームには、因子log 256 / log 62 = 1.344(すべてのバイトシーケンスの平均)の平均長さ拡張が必要です。それ以外の場合、いくつかの鳩がどこかに押しつぶされて死んでしまい、損傷なしでそれらを取り戻すことはできません(つまり、同じにエンコードされた2つの異なる文字列であるため、デコードは確実に機能しません)。

現在、文字列が正確に「一様にランダムなバイトのシーケンス」ではない可能性があります。文字列には何らかの意味があります。つまり、ほとんどのバイトシーケンスは、意味がないために発生しません。それに基づいて、一般的なBase64(または厳密な英数字に固執する必要がある場合はBase62)よりも短い長さの拡張を引き起こすエンコーディングスキームを考案することができます。これはロスレスデータ圧縮です。入力として表示される可能性のある、明確に定義された確率モデルに対して機能します。

概要:一般的な何か少しの長さの延長が今まで発生しないような英数字列に文字列をエンコードするためのスキームは、存在することはできません。それは数学的に不可能です。特定のあなたが期待する入力文字列の種類に合わせた方式では、おそらく存在することができます(ただし、あなたが発生する可能性のある文字列の種類を教えてくれないので、誰もがこの上であなたを助けることができます)。


1
+1、優れた説明。私は知りませんでした=/ ==私は私のニーズのためにこれを回避することができるかもしれ4の倍数になる長さに関連している
阿部Miessler

気を付けて、これは鳩の巣の不足を前提としています。Unicodeにはたくさんの文字があります。実際の問題をよりよく理解する必要があります。
MSalters

@Tom対数除算を使用して平均長さ延長係数をどのように計算しましたか?en.wikipedia.org/wiki/Base64の図に基づいて、エンコードされていない文字ごとにBase64で4/3文字を表すと直感的に理解できます。どうして数学で同じ結論に達したのか不思議に思う...ありがとう:)
ジョナサンリン

私の悪い、愚かな質問。log(256)= 8ビット、log(64)= 6ビット、したがってBase64の比率は8/6 = 4/3 = 1.333です。乾杯。
ジョナサンリン

4

通常、文字の再エンコードは、受信側システムが文字を処理できないときに行われます。たとえば、BASE64は、6ビット(2 6、したがって64)の文字を使用してデータを表し、長いデータシーケンスを表します(末尾に表示されることがある「==」は、位置合わせのためのパディングです)。これは、電子メールの画像ファイルに0xFEが含まれている可能性があり、メールサーバーがそれ(またはその他の従来の非印刷文字)を送信することに不満を感じるためです。

「サイズを縮小する」エンコーディングはありません。エンコーディングとは、ビットとそれらが表す文字との単なるマッピングです。つまり、ASCIIは7ビットの文字セット(エンコード)であり、多くの場合8ビットのスペースに格納されます。受け入れる範囲を制限する場合は、制御文字を除外することもできます。

この方法を使用すると、ビットレベルで書き出す必要があります。また、すべての最新のマシンは8ビットの倍数のアライメントを持っているため、マシンの速度と命令で多少の問題が発生します。たとえば、UnicodeがUTF-8、UTF-16、およびUTF-32である理由です。

セキュリティのためにこれを実行している場合(だからSecurity.SEに投稿したのですか?)、物事を除外して通常どおり保存します。スペースを節約するためにこれを行う場合は、余分なコードとアクセス時間の短縮(ほとんどのエントリがアドレスの境界を越えるため)がスペースを節約する価値があるかどうかを検討してください。

ちなみに、次は8ビットストレージから7ビットにASCIIを変換する必要があったCSコースの抜粋です。

    memset(dest,0x00,8);
    memcpy(dest, source, length);

    for (int i = 0; i < 8; i++) {
            if (dest[i] & 0x80) {
                    fprintf(stderr, "%s: %s\n", dest, "Illegal byte sequence");
                    exit(EILSEQ);
            }
    }

    dest[0] = 0x7F & dest[0] | 0x80 & dest[1] << 7;
    dest[1] = 0x3F & dest[1] >> 1 | 0xC0 & dest[2] << 6;
    dest[2] = 0x1F & dest[2] >> 2 | 0xE0 & dest[3] << 5;
    dest[3] = 0x0F & dest[3] >> 3 | 0xF0 & dest[4] << 4;
    dest[4] = 0x07 & dest[4] >> 4 | 0xF8 & dest[5] << 3;
    dest[5] = 0x03 & dest[5] >> 5 | 0xFC & dest[6] << 2;
    dest[6] = 0x01 & dest[6] >> 6 | 0xFE & dest[7] << 1;
    dest[7] = 0x00; //Clearing out

2

gzip、bzip2、lzmaなどを使用してデータを圧縮し、base64を実行して、使用する文字セットを制限できます。これは、数百バイト以上の大きな文字列でのみ有益です。


1

なぜLZ圧縮を使用しないのですか?これは文字列を圧縮する適切な方法ですが、長い文字列の場合はより効率的です。エンコードするターゲット文字列はどれくらいですか?


LZ圧縮は、attirの提案で言及されているgzipまたはbzip2と比較してどうですか?
NoChance

gzipはLZとハフマンコーディングに基づいています。LZの詳細en.wikipedia.org/wiki/LZ77
A.Rashad
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.