如何在Java中使用Unicode字符填充字符串 String类报告的长度错误组合字符

如何解决如何在Java中使用Unicode字符填充字符串 String类报告的长度错误组合字符

我在字符串中添加右填充以表格式输出

for (String[] tuple : testData) {
  System.out.format("%-32s -> %s\n",tuple[0],tuple[1]);
}

结果如下所示(随机测试数据):

znZfmOEQ0Gb68taaNU6HY21lvo       -> Xq2aGqLedQnTSXg6wmBNDVb
frKweMCH8Kvgyk0J                 -> lHJ5r7YDV0jTL
NxtHP                            -> odvPJklwIzZZ
NX2scXjl5dxWmer                  -> wPDlKCKllVKk
x2HKsSHCqDQ                      -> RMuWLZ2vaP9sOF0yHmjVysJ
b0hryXKd6b80xAI                  -> 05MHjvTOxlxq1bvQ8RGe

当存在多字节unicode字符时,此方法不起作用:

0OZot??ivbyG?hZM1FI?wNhn6r6cC -> OKDxDV1o2NMqXH3VvE7q3uONwEcY5V
fBHRCjU4K8OCdzACmQZSn6WO         -> gvGBtUO5a4gPMKj9BKqBHFKx1iO7
cDUh??b0cXkLWkS                -> SZX
WtP9t                            -> Q0wwoeY3W66mM5rcQQYKpG
va4d?u8SS                       -> KI
a71?⚖TZ??‍♀?ws5J              -> b8A

如您所见,对齐方式已关闭

我的想法是计算String的长度和使用的字节数之间的差,并使用它来抵消填充,如下所示:

int correction = tuple[0].getBytes().length - tuple[0].length();

然后我将填充到32 + correction,而不是填充到32个字符。但是,这也不起作用。

这是我的测试代码(使用emoji-java,但该行为应该可以用任何unicode字符重现):

import java.util.Collection;
import org.apache.commons.lang3.RandomStringUtils;
import com.vdurmont.emoji.Emoji;
import com.vdurmont.emoji.EmojiManager;

public class Test {

  public static void main(String[] args) {
    // create random test data
    String[][] testData = new String[15][2];
    for (String[] tuple : testData) {
      tuple[0] = RandomStringUtils.randomAlphanumeric(2,32);
      tuple[1] = RandomStringUtils.randomAlphanumeric(2,32);
    }

    // add some emojis
    Collection<Emoji> all = EmojiManager.getAll();
    for (String[] tuple : testData) {
      for (int i = 1; i < tuple[0].length(); i++) {
        if (Math.random() > 0.90) {
          Emoji emoji = all.stream().skip((int) (all.size() * Math.random())).findFirst().get();
          tuple[0] = tuple[0].substring(0,i - 1) + emoji.getUnicode() + tuple[0].substring(i + 1);
        }
      }
    }

    // output
    for (String[] tuple : testData) {
      System.out.format("%-32s -> %s\n",tuple[1]);
    }
  }
}

解决方法

实际上,这里存在一些问题,除了某些字体显示的标志比其他字符更宽之外。我假设您要将中国国旗算作一个字符(因为它在屏幕上被绘制为一个元素)。

String类报告的长度错误

String类可用于char,它们是Unicode代码点的16位整数。问题在于,并非所有代码点都适合16位,而只有基本多语言平面(BMP)中的代码点适合于这些char中。 String的{​​{1}}方法返回length()的数量,而不是代码点的数量。

现在,char的{​​{1}}方法在这种情况下可能会有所帮助:它计算给定索引范围内的代码点数。因此,向该方法提供String作为第二个参数将返回代码点的总数。

组合字符

但是,还有另一个问题。例如,“??”中文标志由两个Unicode代码点组成:区域指示符字母C(?,U + 1F1E8)和N(?,U + 1F1F3)。这两个代码点合并成一个中国国旗。这是您无法使用codePointCount方法解决的问题。

区域指示器符号字母seem是一个特殊的场合。这些字符中的两个可以组合成一个国旗。我不知道实现您想要的标准方法。您可能需要手动考虑这一点。

我写了一个小程序来获取字符串的长度。

string.length()
,

正如@Xehpuk所链接的问题中的评论所讨论的那样,在kotlinlang.org上的this discussion以及Daniel Lemire的本博客中,以下似乎是正确的:>

问题是java String类将字符表示为 UTF-16字符。这意味着任何Unicode字符 由16位以上的位表示的另存为2个单独的Char值。 这个事实被String中的许多函数所忽略,例如。 String.lenght不返回Unicode字符数,它 返回字符串中16位字符的数量,一些表情符号 数2个字符。

但是,该行为似乎是特定于实现的。

正如David在他的帖子中提到的,您可以尝试以下操作以获取正确的长度:

tuple.codePointCount(0,tuple.length())

请参见Java SE文档中的code point methods

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?