14

我正面临一种情况,即我在保存到 MySql 5.1 的文本中获取代理字符。由于不支持 UTF-16,因此我想在将其保存到数据库之前通过 java 方法手动删除这些代理对。

我现在已经编写了以下方法,我很想知道是否有直接和最佳的方法来处理这个问题。

在此先感谢您的帮助。

public static String removeSurrogates(String query) {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < query.length() - 1; i++) {
        char firstChar = query.charAt(i);
        char nextChar = query.charAt(i+1);
        if (Character.isSurrogatePair(firstChar, nextChar) == false) {
            sb.append(firstChar);
        } else {
            i++;
        }
    }
    if (Character.isHighSurrogate(query.charAt(query.length() - 1)) == false
            && Character.isLowSurrogate(query.charAt(query.length() - 1)) == false) {
        sb.append(query.charAt(query.length() - 1));
    }

    return sb.toString();
}
4

5 回答 5

8

这里有几件事:

  • Character.isSurrogate(char c)

    char 值是代理代码单元当且仅当它是低代理代码单元或高代理代码单元。

  • 检查对似乎毫无意义,为什么不直接删除所有代理?

  • x == false相当于!x

  • StringBuilder在不需要同步的情况下更好(例如永远不会离开本地范围的变量)。

我建议这样做:

public static String removeSurrogates(String query) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < query.length(); i++) {
        char c = query.charAt(i);
        // !isSurrogate(c) in Java 7
        if (!(Character.isHighSurrogate(c) || Character.isLowSurrogate(c))) {
            sb.append(firstChar);
        }
    }
    return sb.toString();
}

分解if声明

您询问了以下声明:

if (!(Character.isHighSurrogate(c) || Character.isLowSurrogate(c))) {
    sb.append(firstChar);
}

理解它的一种方法是将每个操作分解为它自己的函数,这样您就可以看到该组合符合您的预期:

static boolean isSurrogate(char c) {
    return Character.isHighSurrogate(c) || Character.isLowSurrogate(c);
}

static boolean isNotSurrogate(char c) {
    return !isSurrogate(c);
}

...

if (isNotSurrogate(c)) {
    sb.append(firstChar);
}
于 2012-10-12T21:08:46.660 回答
8

Java 字符串存储为 16 位字符序列,但它们表示的是 unicode 字符序列。在 unicode 术语中,它们存储为代码单元,但模型代码点。因此,谈论删除字符/代码点表示中不存在的代理有点毫无意义(除非您有流氓单个代理,在这种情况下您还有其他问题)。

相反,您要做的是删除编码时需要代理的任何字符。这意味着任何超出基本多语言平面的字符。你可以用一个简单的正则表达式来做到这一点:

return query.replaceAll("[^\u0000-\uffff]", "");
于 2012-10-12T23:13:13.707 回答
2

为什么不简单

for (int i = 0; i < query.length(); i++) 
    char c = query.charAt(i);
    if(!isHighSurrogate(c) && !isLowSurrogate(c))
        sb.append(c);

您可能应该用“?”替换它们,而不是直接擦除它们。

于 2012-10-12T21:07:22.970 回答
1

只是好奇。如果 char 是高代理,是否需要检查下一个?它应该是低代理。修改后的版本将是:

public static String removeSurrogates(String query) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < query.length(); i++) {
        char ch = query.charAt(i);
        if (Character.isHighSurrogate(ch))
            i++;//skip the next char is it's supposed to be low surrogate
        else
            sb.append(ch);
    }    
    return sb.toString();
}
于 2013-01-23T11:26:21.233 回答
0

如果删除,所有这些解决方案都是有用的,但如果 repalce,下面会更好

StringBuffer sb = new StringBuffer();
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if(Character.isHighSurrogate(c)){
            sb.append('*');
        }else if(!Character.isLowSurrogate(c)){
            sb.append(c);
        }
    }
    return sb.toString();
于 2013-11-18T09:29:22.873 回答