【问题标题】:Java find the index of string based on the utf-8 encoding indexJava根据utf-8编码索引查找字符串的索引
【发布时间】:2018-08-06 13:28:49
【问题描述】:

考虑以下字符串:

String text="un’accogliente villa del.";

我有单词“accogliente”的开始索引,即5。但它是基于utf-8编码预先计算的。

我想要 word 的确切索引,即 3 作为输出。即,我想从 5 中得到 3 作为输出。计算它的最佳方法是什么?

【问题讨论】:

  • 如果我理解正确,你为什么不使用indexOf,正确给出3?
  • "un'accogliente villa del.".indexOf("accogliente") == 3
  • 我已经编辑了这个问题。我没有accogliente这个词。我只有 utf-8 的句子和索引,即 5 。从这些值中我需要找到 3. @Eugene
  • 所以你有句子和 startIndex = 5。你想获取包含该 startIndex (5) 的单词所在的索引吗?
  • 我的单词“accogliente”的开始索引是 5 这是什么意思?投票结束,因为不清楚...

标签: java string encoding java-8 byte


【解决方案1】:
String text = "un’accogliente villa del."; // Unicode text
text = Normalizer.normalize(text, Form.NFC); // Normalize text

byte[] bytes = text.getBytes(StandardCharsets.UTF_8); // Index 5 UTF-8; 1 byte
char[] chars = text.toCharArray();                    // Index 3 UTF-16; 2 bytes (indexOf)
int[] codePoints = text.codePoints().toArray();       // Index 3 UTF-32; 4 bytes

int charIndex = text.indexOf("accogliente");
int codePointIndex = (int) text.substring(0, charIndex).codePoints().count();
int byteIndex = text.substring(0, charIndex).getBytes(StandardCharsets.UTF_8).length;

UTF-32 是 Unicode 代码点,所有符号的编号都带有 U+XXXX,其中可能多于(或少于) 4 个十六进制数字。

需要文本规范化,因为é 可以是一个代码点,也可以是两个代码点,一个宽度为零的´,后跟一个e

UTF-8字节索引转UTF-16字符索引的问题:

int charIndex = new String(text.getBytes(StandardCharsets.UTF_8),
                           0, byteIndex, StandardCharsets.UTF_8).length();

【讨论】:

  • @JoopEggen 似乎对 OP 的要求有点不同,他/她有一个startIndex = 5,他必须找到包含这个字母的单词(我首先假设),然后剥离非 ascii 字母找到该单词所在的索引。我认为这是他需要的
  • @TweetMan 抱歉打错了,java.text.Normalizerjava.text.Normalizer.Form.NFKC;对于问题的文本规范化并不是真正需要的。
  • @Eugene 他提到 UTF-8 似乎表明 5 是acco 的字节索引。尤其是特殊引号 U+2019 在 UTF-8 中确实是 3 个字节长。
【解决方案2】:

下面的代码将返回输出为3我在你的问题中遗漏了什么吗?

String text="un’accogliente villa del.";
text.indexOf("accogliente");

【讨论】:

  • OP 解释说这不是他想要的。
  • 是的..明白了! @Glains
【解决方案3】:

假设这个startIndex 只能是一个字母(ASCII 码),你可以这样做:

String text = "un’accogliente villa del.";
char c = text.charAt(5);
String normalized = Normalizer.normalize(text, Normalizer.Form.NFD);
normalized = normalized.replaceAll("[^\\p{ASCII}]", " ");

Pattern p = Pattern.compile("\\p{L}*?" + c + "\\p{L}*?[$|\\s]");
Matcher m = p.matcher(normalized);

if (m.find()) {
     System.out.println(m.start(0));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-15
    • 2018-11-06
    • 1970-01-01
    • 1970-01-01
    • 2015-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多