US-ASCII字符串(解)压缩into/from一个字节数组(7bits/character)
US-ASCII string (de-)compression into/from a byte array (7 bits/character)
众所周知,ASCII 使用 7 位来编码字符,因此用于表示文本的字节数总是小于文本字母的长度
例如:
StringBuilder text = new StringBuilder();
IntStream.range(0, 160).forEach(x -> text.append("a")); // generate 160 text
int letters = text.length();
int bytes = text.toString().getBytes(StandardCharsets.US_ASCII).length;
System.out.println(letters); // expected 160, actual 160
System.out.println(bytes); // expected 140, actual 160
总是 letters
= bytes
,但预期是 letters
> bytes
。
主要问题: in smpp
protocol sms
body must be <= 140
byte, if we used ascii
encoding , 然后你可以写 160
个字母 =(140*8/7)
, 所以我想用 7-bit based ascii
编码的文本, 我们正在使用 JSMPP
库
任何人都可以向我解释并指导我正确的方法,在此先感谢(:
根据编码类型,字节长度会有所不同。检查下面的例子。
String text = "0123456789";
byte[] b1 = text.getBytes(StandardCharsets.US_ASCII);
System.out.println(b1.length);
// prints "10"
byte[] utf8 = text.getBytes(StandardCharsets.UTF_8);
System.out.println(utf8.length);
// prints "10"
byte[] utf16= text.getBytes(StandardCharsets.UTF_16);
System.out.println(utf16.length);
// prints "22"
byte[] utf32 = text.getBytes(StandardCharsets.ISO_8859_1);
System.out.println(utf32.length);
// prints "10"
(160*7-160*8)/8 = 20,因此您预计脚本末尾使用的字节数会减少 20 个。但是,寄存器有一个最小大小,所以即使你不使用所有位,你仍然不能将它连接到另一个值,所以你仍然使用 8 位字节作为你的 ASCII 码,这就是为什么你得到相同的号码。比如小写的"a"在ASCII
中就是97
01100001
请注意前导零仍然存在,即使它没有被使用。你不能只用它来存储另一个值的一部分。
结论是,在纯 ASCII 中,字母必须始终等于字节数。
(或者想象一下将 7 号物体放入 8 号盒子中。您不能将物体劈成碎片,因此盒子的数量必须等于物体的数量 - 至少在这种情况下。)
没有。在 "modern" 环境中(从 3 或 4 年前开始),ASCII 字符集的 ASCII 字符编码使用 8 位代码单元,然后将其序列化为每个字节。这是因为我们要在 "octets"(8 位字节)中移动和存储数据。这种字符编码恰好总是将高位设置为 0。
可以说,很久以前就有一种用于 ASCII 字符集的 7 位字符编码。即使那样,数据也可能已作为八位字节移动或存储。高位将用于某些 application-specific 目的,例如奇偶校验。某些系统会将其归零以尝试提高互操作性,但最终由于不是“8 位安全”而阻碍了互操作性。有了强大的互联网标准,这样的系统几乎都成为过去。
这是一个没有任何库的快速而肮脏的解决方案,即只有 JRE on-board 手段。它没有针对效率进行优化,并且不检查消息是否确实是 US-ASCII,它只是假设它。这只是一个概念证明:
package de.scrum_master.Whosebug;
import java.util.BitSet;
public class ASCIIConverter {
public byte[] compress(String message) {
BitSet bits = new BitSet(message.length() * 7);
int currentBit = 0;
for (char character : message.toCharArray()) {
for (int bitInCharacter = 0; bitInCharacter < 7; bitInCharacter++) {
if ((character & 1 << bitInCharacter) > 0)
bits.set(currentBit);
currentBit++;
}
}
return bits.toByteArray();
}
public String decompress(byte[] compressedMessage) {
BitSet bits = BitSet.valueOf(compressedMessage);
int numBits = 8 * compressedMessage.length - compressedMessage.length % 7;
StringBuilder decompressedMessage = new StringBuilder(numBits / 7);
for (int currentBit = 0; currentBit < numBits; currentBit += 7) {
char character = (char) bits.get(currentBit, currentBit + 7).toByteArray()[0];
decompressedMessage.append(character);
}
return decompressedMessage.toString();
}
public static void main(String[] args) {
String[] messages = {
"Hello world!",
"This is my message.\n\tAnd this is indented!",
" !\"#$%&'()*+,-./0123456789:;<=>?\n"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_\n"
+ "`abcdefghijklmnopqrstuvwxyz{|}~",
"1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890"
};
ASCIIConverter asciiConverter = new ASCIIConverter();
for (String message : messages) {
System.out.println(message);
System.out.println("--------------------------------");
byte[] compressedMessage = asciiConverter.compress(message);
System.out.println("Number of ASCII characters = " + message.length());
System.out.println("Number of compressed bytes = " + compressedMessage.length);
System.out.println("--------------------------------");
System.out.println(asciiConverter.decompress(compressedMessage));
System.out.println("\n");
}
}
}
控制台日志如下所示:
Hello world!
--------------------------------
Number of ASCII characters = 12
Number of compressed bytes = 11
--------------------------------
Hello world!
This is my message.
And this is indented!
--------------------------------
Number of ASCII characters = 42
Number of compressed bytes = 37
--------------------------------
This is my message.
And this is indented!
!"#$%&'()*+,-./0123456789:;<=>?
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
`abcdefghijklmnopqrstuvwxyz{|}~
--------------------------------
Number of ASCII characters = 97
Number of compressed bytes = 85
--------------------------------
!"#$%&'()*+,-./0123456789:;<=>?
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
`abcdefghijklmnopqrstuvwxyz{|}~
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
--------------------------------
Number of ASCII characters = 160
Number of compressed bytes = 140
--------------------------------
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
众所周知,ASCII 使用 7 位来编码字符,因此用于表示文本的字节数总是小于文本字母的长度
例如:
StringBuilder text = new StringBuilder();
IntStream.range(0, 160).forEach(x -> text.append("a")); // generate 160 text
int letters = text.length();
int bytes = text.toString().getBytes(StandardCharsets.US_ASCII).length;
System.out.println(letters); // expected 160, actual 160
System.out.println(bytes); // expected 140, actual 160
总是 letters
= bytes
,但预期是 letters
> bytes
。
主要问题: in smpp
protocol sms
body must be <= 140
byte, if we used ascii
encoding , 然后你可以写 160
个字母 =(140*8/7)
, 所以我想用 7-bit based ascii
编码的文本, 我们正在使用 JSMPP
库
任何人都可以向我解释并指导我正确的方法,在此先感谢(:
根据编码类型,字节长度会有所不同。检查下面的例子。
String text = "0123456789";
byte[] b1 = text.getBytes(StandardCharsets.US_ASCII);
System.out.println(b1.length);
// prints "10"
byte[] utf8 = text.getBytes(StandardCharsets.UTF_8);
System.out.println(utf8.length);
// prints "10"
byte[] utf16= text.getBytes(StandardCharsets.UTF_16);
System.out.println(utf16.length);
// prints "22"
byte[] utf32 = text.getBytes(StandardCharsets.ISO_8859_1);
System.out.println(utf32.length);
// prints "10"
(160*7-160*8)/8 = 20,因此您预计脚本末尾使用的字节数会减少 20 个。但是,寄存器有一个最小大小,所以即使你不使用所有位,你仍然不能将它连接到另一个值,所以你仍然使用 8 位字节作为你的 ASCII 码,这就是为什么你得到相同的号码。比如小写的"a"在ASCII
中就是9701100001
请注意前导零仍然存在,即使它没有被使用。你不能只用它来存储另一个值的一部分。
结论是,在纯 ASCII 中,字母必须始终等于字节数。
(或者想象一下将 7 号物体放入 8 号盒子中。您不能将物体劈成碎片,因此盒子的数量必须等于物体的数量 - 至少在这种情况下。)
没有。在 "modern" 环境中(从 3 或 4 年前开始),ASCII 字符集的 ASCII 字符编码使用 8 位代码单元,然后将其序列化为每个字节。这是因为我们要在 "octets"(8 位字节)中移动和存储数据。这种字符编码恰好总是将高位设置为 0。
可以说,很久以前就有一种用于 ASCII 字符集的 7 位字符编码。即使那样,数据也可能已作为八位字节移动或存储。高位将用于某些 application-specific 目的,例如奇偶校验。某些系统会将其归零以尝试提高互操作性,但最终由于不是“8 位安全”而阻碍了互操作性。有了强大的互联网标准,这样的系统几乎都成为过去。
这是一个没有任何库的快速而肮脏的解决方案,即只有 JRE on-board 手段。它没有针对效率进行优化,并且不检查消息是否确实是 US-ASCII,它只是假设它。这只是一个概念证明:
package de.scrum_master.Whosebug;
import java.util.BitSet;
public class ASCIIConverter {
public byte[] compress(String message) {
BitSet bits = new BitSet(message.length() * 7);
int currentBit = 0;
for (char character : message.toCharArray()) {
for (int bitInCharacter = 0; bitInCharacter < 7; bitInCharacter++) {
if ((character & 1 << bitInCharacter) > 0)
bits.set(currentBit);
currentBit++;
}
}
return bits.toByteArray();
}
public String decompress(byte[] compressedMessage) {
BitSet bits = BitSet.valueOf(compressedMessage);
int numBits = 8 * compressedMessage.length - compressedMessage.length % 7;
StringBuilder decompressedMessage = new StringBuilder(numBits / 7);
for (int currentBit = 0; currentBit < numBits; currentBit += 7) {
char character = (char) bits.get(currentBit, currentBit + 7).toByteArray()[0];
decompressedMessage.append(character);
}
return decompressedMessage.toString();
}
public static void main(String[] args) {
String[] messages = {
"Hello world!",
"This is my message.\n\tAnd this is indented!",
" !\"#$%&'()*+,-./0123456789:;<=>?\n"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_\n"
+ "`abcdefghijklmnopqrstuvwxyz{|}~",
"1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890"
+ "1234567890123456789012345678901234567890"
};
ASCIIConverter asciiConverter = new ASCIIConverter();
for (String message : messages) {
System.out.println(message);
System.out.println("--------------------------------");
byte[] compressedMessage = asciiConverter.compress(message);
System.out.println("Number of ASCII characters = " + message.length());
System.out.println("Number of compressed bytes = " + compressedMessage.length);
System.out.println("--------------------------------");
System.out.println(asciiConverter.decompress(compressedMessage));
System.out.println("\n");
}
}
}
控制台日志如下所示:
Hello world!
--------------------------------
Number of ASCII characters = 12
Number of compressed bytes = 11
--------------------------------
Hello world!
This is my message.
And this is indented!
--------------------------------
Number of ASCII characters = 42
Number of compressed bytes = 37
--------------------------------
This is my message.
And this is indented!
!"#$%&'()*+,-./0123456789:;<=>?
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
`abcdefghijklmnopqrstuvwxyz{|}~
--------------------------------
Number of ASCII characters = 97
Number of compressed bytes = 85
--------------------------------
!"#$%&'()*+,-./0123456789:;<=>?
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
`abcdefghijklmnopqrstuvwxyz{|}~
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
--------------------------------
Number of ASCII characters = 160
Number of compressed bytes = 140
--------------------------------
1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890