【问题标题】:how to distinguish Unicode characters and ASCII characters如何区分 Unicode 字符和 ASCII 字符
【发布时间】:2018-01-22 03:11:45
【问题描述】:

我想从下面的字符串中区分 Unicode 字符和 ASCII 字符:

abc\u263A\uD83D\uDE0A\uD83D\uDE22123

如何区分字符?谁能帮我解决这个问题?我尝试了一些代码,但在某些情况下它会崩溃。我的代码有什么问题?

前三个字符是abc,后三个字符是123。字符串的其余部分是 Unicode 字符。我想做一个这样的字符串数组:

str[0] = 'a';
str[1] = 'b';
str[2] = 'c';
str[3] = '\u263A\uD83D';
str[4] = '\uDE0A\uD83D';
str[5] = '\uDE22';
str[6] = '1';
str[7] = '2';
str[8] = '3';

代码:

private String[] getCharArray(String unicodeStr) {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < unicodeStr.length(); i++) {
            if (unicodeStr.charAt(i) == '\\') {
                list.add(unicodeStr.substring(i, i + 11));
                i = i + 11;
            } else {
                list.add(String.valueOf(unicodeStr.charAt(i)));
            }
        }
        return list.toArray(new String[list.size()]);
    }

【问题讨论】:

标签: java string unicode char ascii


【解决方案1】:

目前尚不完全清楚您要求的是什么,但如果您想判断某个特定字符是否为 ASCII,您可以使用Guava's ChatMatcher.ascii()

if ( CharMatcher.ascii().matches('a') ) {
    System.out.println("'a' is ascii");
}
if ( CharMatcher.ascii().matches('\u263A\uD83D') ) {
    // this shouldn't be printed
    System.out.println("'\u263A\uD83D' is ascii");
}

【讨论】:

    【解决方案2】:

    ASCII 字符存在于 Unicode 中,它们是 Unicode 代码点 U+0000 - U+007F,包括在内。

    Java 字符串以 UTF-16 表示,它是 Unicode 的 16 位字节编码。每个 Java char 都是一个 UTF-16 代码单元。 Unicode 代码点 U+0000 - U+FFFF 使用 1 个 UTF-16 代码单元,因此适合单个 char,而 Unicode 代码点 U+10000 和更高版本需要 UTF-16 代理对,因此需要两个chars。

    如果字符串具有表示为实际 char 值的 UTF-16 代码单元,那么您可以使用 Java 的 string 处理代码点的方法,例如:

    private String[] getCharArray(String unicodeStr) {
        ArrayList<String> list = new ArrayList<>();
        int i = 0, j;
        while (i < unicodeStr.length()) {
            j = unicodeStr.offsetByCodePoints(i, 1);
            list.add(unicodeStr.substring(i, j));
            i = j;
        }
        return list.toArray(new String[list.size()]);
    }
    

    另一方面,如果字符串具有以编码 "\uXXXX" 格式表示的 UTF-16 代码单元(即,作为 6 个不同的字符 - '\''u'、...),那么事情会得到稍微复杂一点,因为您必须手动解析编码序列。

    如果你想在你的数组中保留 "\uXXXX" 字符串,你可以这样做:

    private boolean isUnicodeEncoded(string s, int index)
    {
        return (
            (s.charAt(index) == '\\') &&
            ((index+5) < s.length()) &&
            (s.charAt(index+1) == 'u')
        );
    }
    
    private String[] getCharArray(String unicodeStr) {
        ArrayList<String> list = new ArrayList<>();
        int i = 0, j, start;
        char ch;
        while (i < unicodeStr.length()) {
            start = i;
            if (isUnicodeEncoded(unicodeStr, i)) {
                ch = (char) Integer.parseInt(unicodeStr.substring(i+2, i+6), 16);
                j = 6;
            }
            else {
                ch = unicodeStr.charAt(i);
                j = 1;
            }
            i += j;
            if (Character.isHighSurrogate(ch) && (i < unicodeStr.length())) {
                if (isUnicodeEncoded(unicodeStr, i)) {
                    ch = (char) Integer.parseInt(unicodeStr.substring(i+2, i+6), 16);
                    j = 6;
                }
                else {
                    ch = unicodeStr.charAt(i);
                    j = 1;
                }
                if (Character.isLowSurrogate(ch)) {
                    i += j;
                }
            }
            list.add(unicodeStr.substring(start, i));
        }
        return list.toArray(new String[list.size()]);
    }
    

    如果您想将“\uXXXX”字符串解码为数组中的实际字符,您可以执行以下操作:

    private boolean isUnicodeEncoded(string s, int index)
    {
        return (
            (s.charAt(index) == '\\') &&
            ((index+5) < s.length()) &&
            (s.charAt(index+1) == 'u')
        );
    }
    
    private String[] getCharArray(String unicodeStr) {
        ArrayList<String> list = new ArrayList<>();
        int i = 0, j;
        char ch1, ch2;
        while (i < unicodeStr.length()) {
            if (isUnicodeEncoded(unicodeStr, i)) {
                ch1 = (char) Integer.parseInt(unicodeStr.substring(i+2, i+6), 16);
                j = 6;
            }
            else {
                ch1 = unicodeStr.charAt(i);
                j = 1;
            }
            i += j;
            if (Character.isHighSurrogate(ch1) && (i < unicodeStr.length())) {
                if (isUnicodeEncoded(unicodeStr, i)) {
                    ch2 = (char) Integer.parseInt(unicodeStr.substring(i+2, i+6), 16);
                    j = 6;
                }
                else {
                    ch2 = unicodeStr.charAt(i);
                    j = 1;
                }
                if (Character.isLowSurrogate(ch2)) {
                    list.add(String.valueOf(new char[]{ch1, ch2}));
                    i += j;
                    continue;
                }
            }
            list.add(String.valueOf(ch1));
        }
        return list.toArray(new String[list.size()]);
    }
    

    或者,像这样(根据https://stackoverflow.com/a/24046962/65863):

    private String[] getCharArray(String unicodeStr) {
        Properties p = new Properties();
        p.load(new StringReader("key="+unicodeStr));
        unicodeStr = p.getProperty("key");
        ArrayList<String> list = new ArrayList<>();
        int i = 0;
        while (i < unicodeStr.length()) {
            if (Character.isHighSurrogate(unicodeStr.charAt(i)) &&
                ((i+1) < unicodeStr.length()) &&
                Character.isLowSurrogate(unicodeStr.charAt(i+1)))
            {
                list.add(unicodeStr.substring(i, i+2));
                i += 2;
            }
            else {
                list.add(unicodeStr.substring(i, i+1));
                ++i;
            }
        }
        return list.toArray(new String[list.size()]);
    }
    

    【讨论】:

      猜你喜欢
      • 2013-04-17
      • 1970-01-01
      • 2011-02-07
      • 2012-05-08
      • 1970-01-01
      • 1970-01-01
      • 2010-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多