按字节截断字符串

9

我创建了以下代码用于在Java中将字符串截断为给定字节数的新字符串。

        String truncatedValue = "";
        String currentValue = string;
        int pivotIndex = (int) Math.round(((double) string.length())/2);
        while(!truncatedValue.equals(currentValue)){
            currentValue = string.substring(0,pivotIndex);
            byte[] bytes = null;
            bytes = currentValue.getBytes(encoding);
            if(bytes==null){
                return string;
            }
            int byteLength = bytes.length;
            int newIndex =  (int) Math.round(((double) pivotIndex)/2);
            if(byteLength > maxBytesLength){
                pivotIndex = newIndex;
            } else if(byteLength < maxBytesLength){
                pivotIndex = pivotIndex + 1;
            } else {
                truncatedValue = currentValue;
            }
        }
        return truncatedValue;

这是我想到的第一件事,我知道我可以改进它。我看到另一篇帖子在问类似的问题,但他们是使用字节来截取字符串而不是使用String.substring。我认为在我的情况下我更愿意使用String.substring

编辑:我刚刚删除了UTF8的参考,因为我也想能够适用于不同的存储类型。


我会重新表述您的问题。您正在尝试将一个字符串适配到一个字节数组中,但该数组大小不能大于maxUTF8BytesLength。您想要使用UTF-8进行编码,并尽可能复制尽可能多的字符。是这样吗? - gawi
正确,我会说那是正确的。我也希望能够高效地完成它。 - stevebot
我刚刚编辑了问题,不再提及UTF-8。对此我感到抱歉,这是误导性的。 - stevebot
12个回答

0

我改进了Peter Lawrey的解决方案以准确处理代理对。此外,我基于UTF-8编码中每个char的最大字节数为3进行了优化。

public static String substring(String text, int maxBytes) {
    for (int i = 0, len = text.length(); (len - i) * 3 > maxBytes;) {
        int j = text.offsetByCodePoints(i, 1);
        if ((maxBytes -= text.substring(i, j).getBytes(StandardCharsets.UTF_8).length) < 0)  
            return text.substring(0, i);
        i = j;
    }
    return text;
}

0

Scala 中的二分查找方法:

private def bytes(s: String) = s.getBytes("UTF-8")

def truncateToByteLength(string: String, length: Int): String =
  if (length <= 0 || string.isEmpty) ""
  else {
    @tailrec
    def loop(badLen: Int, goodLen: Int, good: String): String = {
      assert(badLen > goodLen, s"""badLen is $badLen but goodLen is $goodLen ("$good")""")
      if (badLen == goodLen + 1) good
      else {
        val mid = goodLen + (badLen - goodLen) / 2
        val midStr = string.take(mid)
        if (bytes(midStr).length > length)
          loop(mid, goodLen, good)
        else
          loop(badLen, mid, midStr)
      }
    }

    loop(string.length * 2, 0, "")
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接