はい、以前の 3 文字の値のエンコードを維持しながら、余分な情報をエンコードすることは可能です。ただし、元のエンコーディングでは出力セットに自由な数字のきれいな帯が残らないため、その余分な文字を追加することによって導入された追加の文字列セットのマッピングは、少し不連続になるしかありません。
したがって、これらの不連続性をぎこちなく遅く処理するマッピング関数を考え出すのは難しいと思います。私は、テーブルベースのマッピングが唯一の適切なソリューションであると結論付けています。
私はあなたのマッピング コードを再設計するのが面倒だったので、それを私のテーブル初期化コードに組み込みました。これにより、翻訳エラーの多くの機会も排除されます:) あなたのencode()方法は私が呼ぶものOldEncoder.encode()です.
小さなテスト プログラムを実行しNewEncoder.encode()て、 と同じ値が得られることを確認しOldEncoder.encode()、さらに先頭の 4 番目の文字で文字列をエンコードできることを確認しました。NewEncoder.encode()文字が何であるかは気にしません。文字列の長さで決まります。の場合decode()、使用する文字は を使用して定義できますPREFIX_CHAR。また、接頭辞付き文字列のバイト配列値が、接頭辞なし文字列のバイト配列値と重複していないことも確認しました。そして最後に、エンコードされた接頭辞付き文字列は実際に同じ接頭辞付き文字列に戻すことができます。
package tequilaguy;
public class NewConverter {
private static final String[] b2s = new String[0x10000];
private static final int[] s2b = new int[0x10000];
static {
createb2s();
creates2b();
}
/**
* Create the "byte to string" conversion table.
*/
private static void createb2s() {
// Fill 17576 elements of the array with b -> s equivalents.
// index is the combined byte value of the old encode fn;
// value is the String (3 chars).
for (char a='A'; a<='Z'; a++) {
for (char b='A'; b<='Z'; b++) {
for (char c='A'; c<='Z'; c++) {
String str = new String(new char[] { a, b, c});
byte[] enc = OldConverter.encode(str);
int index = ((enc[0] & 0xFF) << 8) | (enc[1] & 0xFF);
b2s[index] = str;
// int value = 676 * a + 26 * b + c - ((676 + 26 + 1) * 'A'); // 45695;
// System.out.format("%s : %02X%02X = %04x / %04x %n", str, enc[0], enc[1], index, value);
}
}
}
// Fill 17576 elements of the array with b -> @s equivalents.
// index is the next free (= not null) array index;
// value = the String (@ + 3 chars)
int freep = 0;
for (char a='A'; a<='Z'; a++) {
for (char b='A'; b<='Z'; b++) {
for (char c='A'; c<='Z'; c++) {
String str = "@" + new String(new char[] { a, b, c});
while (b2s[freep] != null) freep++;
b2s[freep] = str;
// int value = 676 * a + 26 * b + c - ((676 + 26 + 1) * 'A') + (26 * 26 * 26);
// System.out.format("%s : %02X%02X = %04x / %04x %n", str, 0, 0, freep, value);
}
}
}
}
/**
* Create the "string to byte" conversion table.
* Done by inverting the "byte to string" table.
*/
private static void creates2b() {
for (int b=0; b<0x10000; b++) {
String s = b2s[b];
if (s != null) {
int sval;
if (s.length() == 3) {
sval = 676 * s.charAt(0) + 26 * s.charAt(1) + s.charAt(2) - ((676 + 26 + 1) * 'A');
} else {
sval = 676 * s.charAt(1) + 26 * s.charAt(2) + s.charAt(3) - ((676 + 26 + 1) * 'A') + (26 * 26 * 26);
}
s2b[sval] = b;
}
}
}
public static byte[] encode(String str) {
int sval;
if (str.length() == 3) {
sval = 676 * str.charAt(0) + 26 * str.charAt(1) + str.charAt(2) - ((676 + 26 + 1) * 'A');
} else {
sval = 676 * str.charAt(1) + 26 * str.charAt(2) + str.charAt(3) - ((676 + 26 + 1) * 'A') + (26 * 26 * 26);
}
int bval = s2b[sval];
return new byte[] { (byte) (bval >> 8), (byte) (bval & 0xFF) };
}
public static String decode(byte[] b) {
int bval = ((b[0] & 0xFF) << 8) | (b[1] & 0xFF);
return b2s[bval];
}
}
コード内にいくつかの複雑な定数式、特に 26 の累乗のものを残しました。それ以外の場合、コードは恐ろしく神秘的に見えます。コンパイラは Kleenex のようにそれらを折りたたむので、パフォーマンスを失うことなくそれらをそのままにしておくことができます。
アップデート:
クリスマスの恐怖が近づくにつれ、私はしばらく旅に出ます。この回答とコードが間に合うように見つかり、それを有効に活用できることを願っています。この取り組みをサポートするために、小さなテスト プログラムを投入します。直接チェックするのではなく、変換結果をすべての重要な方法で出力し、それらを目と手でチェックできるようにします。すべてが問題ないように見えるまで、コードをいじりました(基本的なアイデアを理解したら、小さな調整を加えました)。より機械的かつ徹底的にテストすることをお勧めします。
package tequilaguy;
public class ConverterHarness {
// private static void runOldEncoder() {
// for (char a='A'; a<='Z'; a++) {
// for (char b='A'; b<='Z'; b++) {
// for (char c='A'; c<='Z'; c++) {
// String str = new String(new char[] { a, b, c});
// byte[] enc = OldConverter.encode(str);
// System.out.format("%s : %02X%02X%n", str, enc[0], enc[1]);
// }
// }
// }
// }
private static void testNewConverter() {
for (char a='A'; a<='Z'; a++) {
for (char b='A'; b<='Z'; b++) {
for (char c='A'; c<='Z'; c++) {
String str = new String(new char[] { a, b, c});
byte[] oldEnc = OldConverter.encode(str);
byte[] newEnc = NewConverter.encode(str);
byte[] newEnc2 = NewConverter.encode("@" + str);
System.out.format("%s : %02X%02X %02X%02X %02X%02X %s %s %n",
str, oldEnc[0], oldEnc[1], newEnc[0], newEnc[1], newEnc2[0], newEnc2[1],
NewConverter.decode(newEnc), NewConverter.decode(newEnc2));
}
}
}
}
public static void main(String[] args) {
testNewConverter();
}
}