如何在 Java 中正确计算字符串的长度?

新手上路,请多包涵

我知道有 String#lengthCharacter 中的各种方法,它们或多或少地在代码单元/代码点上工作。

在 Java 中实际返回 Unicode 标准 ( UAX#29 ) 指定的结果的建议方法是什么,同时考虑语言/区域设置、规范化和字素集群等因素?

原文由 soc 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

java.text.BreakIterator 能够遍历文本并报告“字符”、单词、句子和行边界。

考虑这段代码:

 def length(text: String, locale: java.util.Locale = java.util.Locale.ENGLISH) = {
  val charIterator = java.text.BreakIterator.getCharacterInstance(locale)
  charIterator.setText(text)

  var result = 0
  while(charIterator.next() != BreakIterator.DONE) result += 1
  result
}

运行它:

 scala> val text = "Thîs lóo̰ks we̐ird!"
text: java.lang.String = Thîs lóo̰ks we̐ird!

scala> val length = length(text)
length: Int = 17

scala> val codepoints = text.codePointCount(0, text.length)
codepoints: Int = 21

使用代理对:

 scala> val parens = "\uDBFF\uDFFCsurpi\u0301se!\uDBFF\uDFFD"
parens: java.lang.String = 􏿼surpíse!􏿽

scala> val length = length(parens)
length: Int = 10

scala> val codepoints = parens.codePointCount(0, parens.length)
codepoints: Int = 11

scala> val codeunits = parens.length
codeunits: Int = 13

在大多数情况下,这应该可以完成工作。

原文由 soc 发布,翻译遵循 CC BY-SA 3.0 许可协议

Java字符串长度的正常模型

String.length() 指定 为返回字符串中 char 值(“代码单元”)的数量。这是对 Java String 长度 最普遍有用 的定义;见下文。

您对 length 语义的描述1基于支持数组/数组切片的大小是不正确的。事实上, length() 返回的值 也是 支持数组或数组切片的大小,这 只是 典型 Java 类库的一个实现细节。 String 不需要那样实现。事实上,我想我已经看到了 Java String 实现,但它并没有以这种方式实现。


字符串长度的替代模型。

要获取字符串中 Unicode 代码点的数量,请使用 str.codePointCount(0, str.length()) 请参阅 javadoc

要获取特定编码(即字符集)中字符串的大小(以字节为单位),请使用 str.getBytes(charset).length 2 。

要处理特定于语言环境的问题,您可以使用 Normalizer 将字符串规范化为最适合您的用例的任何形式,然后使用 codePointCount 如上所述。但在某些情况下,即使这样也行不通;例如,Unicode 标准显然不符合匈牙利字母计数规则。


使用 String.length() 一般都可以

大多数应用程序使用 String.length() 的原因是大多数应用程序不关心以人为中心的方式计算单词、文本等中的字符数。例如,如果我这样做:

 String s = "hi mum how are you";
int pos = s.indexOf("mum");
String textAfterMum = s.substring(pos + "mum".length());

"mum".length() 没有返回代码点或者它不是语言上正确的字符计数真的无关紧要。它使用适合手头任务的模型测量字符串的长度。它有效。

显然,当您进行多语言文本分析时,事情会变得有点复杂;例如搜索单词。但即便如此,如果您在开始之前对文本和参数进行规范化,则大多数时候您可以安全地使用“代码单元”而不是“代码点”进行编码;即 length() 仍然有效。


1 - 此描述是针对问题的某些版本。查看编辑历史……如果您有足够的代表点数。

2 - 使用 str.getBytes(charset).length 需要进行编码并将其丢弃。如果没有该副本,可能有一种 通用 的方法可以做到这一点。 It would entail wrapping the String as a CharBuffer , creating a custom ByteBuffer with no backing to act as a byte counter, and then using Encoder.encode(...) 计算字节数。注意:我没有尝试过这个,我不建议尝试 ,除非 你有明确的证据表明 getBytes(charset) 是一个重要的性能瓶颈。

原文由 Stephen C 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题