1

众所周知,ASCII使用7位编码chars,所以用来表示文本的字节数总是小于文本字母的长度

例如:

    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

主要问题:smpp协议正文中sms必须是<= 140字节,如果我们使用ascii编码,那么你可以写160字母=(140*8/7),所以我想文本编码7-bit based ascii,我们使用JSMPP

任何人都可以向我解释并指导我正确的方式,在此先感谢(:

4

4 回答 4

2

(160*7-160*8)/8 = 20,因此您预计脚本结束时会少用 20 个字节。但是,寄存器有一个最小大小,所以即使你不使用所有位,你仍然不能将它连接到另一个值,所以你的 ASCII 代码仍然使用 8 位字节,这就是为什么你得到相同的数字。例如,小写的“a”在 ASCII 中是 97

‭01100001‬

请注意,前导零仍然存在,即使它没有被使用。您不能只使用它来存储另一个值的一部分。

综上所述,纯 ASCII 字母必须始终等于字节。

(或者想象将 7 号物体放入 8 号盒子中。你不能将物体砍成碎片,所以盒子的数量必须等于物体的数量——至少在这种情况下是这样。)

于 2019-07-04T09:52:19.550 回答
1

这是一个没有任何库的快速而肮脏的解决方案,即只有 JRE 板载方式。它没有针对效率进行优化,并且不检查消息是否确实是 US-ASCII,它只是假设它。这只是一个概念证明:

package de.scrum_master.stackoverflow;

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
于 2019-07-05T06:04:46.560 回答
0

没有。在“现代”环境中(从 3 年或 4 年前开始),ASCII 字符集的 ASCII 字符编码使用 8 位代码单元,然后每个代码单元被序列化为一个字节。这是因为我们希望以“八位字节”(8 位字节)的形式移动和存储数据。这种字符编码恰好总是将高位设置为 0。

可以说,很久以前就有 7 位字符编码用于 ASCII 字符集。即使这样,数据也可能已被移动或存储为八位字节。高位将用于某些特定于应用程序的目的,例如奇偶校验。一些系统会将其归零以试图增加互操作性,但最终由于不是“8位安全”而阻碍了互操作性。有了强大的互联网标准,这样的系统几乎都是过去式了。

于 2019-07-04T12:20:40.560 回答
0

根据编码类型,字节长度会有所不同。检查以下示例。

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" 
于 2019-07-04T09:50:49.983 回答