如何替换Java中不可打印的Unicode字符?


88

以下内容将替换ASCII控制字符(的缩写[\x00-\x1F\x7F]):

my_string.replaceAll("\\p{Cntrl}", "?");

以下内容将替换所有ASCII不可打印字符(的缩写[\p{Graph}\x20]),包括带重音符号的字符:

my_string.replaceAll("[^\\p{Print}]", "?");

但是,两者均不适用于Unicode字符串。有谁能从Unicode字符串中删除不可打印的字符的好方法?


2
正如增编:Unicode通用类别列表中可以找到UAX#44
麦克道尔


1
@Stewart:嗨,您看标题旁的问题了吗?!
dagnelies

1
@Stewart:那另一个问题只涵盖了不可打印字符的ascii子集!!!
dagnelies,2013年

Answers:


134
my_string.replaceAll("\\p{C}", "?");

详细了解Unicode正则表达式java.util.regexPattern/String.replaceAll支持他们。


至少在Java 1.6中,不支持它们。download.oracle.com/javase/6/docs/api/java/util/regex / ... ...我也尝试了一下,除了缺少反斜杠外,它显然根本行不通。
dagnelies 2011年

这行得通:char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?");Unicode支持部分的模式文档的javadoc中,也说它支持以下类别
Op De Cirkel

你是对的!我道歉。我没有注意到它,因为我不得不添加Zl Zp类别,因为这些主要是问题的根源。完美运作。您能否对您的帖子进行迷你编辑,以便我可以再次投票?
dagnelies 2011年

6
还有一些不可见的空格字符(例如0x0200B),它们是\ p {Zs}组的一部分。不幸的是,这个也包括普通的空格。对于那些试图过滤不应包含任何空格的输入字符串的人而言,该字符串s.replaceAll("[\\p{C}\\p{Z}]", "")将具有吸引力
Andrey L

1
这就是我一直在寻找的东西,我一直在尝试replaceAll("[^\\u0000-\\uFFFF]", "")但没有成功
Bibaswann Bandyopadhyay

58

Op De Cirkel基本上是正确的。他的建议在大多数情况下都会起作用:

myString.replaceAll("\\p{C}", "?");

但是,如果myString可能包含非BMP代码点,则更为复杂。 \p{C}包含的替代代码点\p{Cs}。上面的替换方法有时会仅替换代理对的一半来破坏非BMP代码点。这可能是Java错误,而不是预期的行为。

使用其他组成类别是一种选择:

myString.replaceAll("[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]", "?");

但是,不删除不属于一对的单独替代字符(每个替代字符都有一个分配的代码点)。我知道正确处理非正则表达式的唯一方法是\p{C}

StringBuilder newString = new StringBuilder(myString.length());
for (int offset = 0; offset < myString.length();)
{
    int codePoint = myString.codePointAt(offset);
    offset += Character.charCount(codePoint);

    // Replace invisible control characters and unused code points
    switch (Character.getType(codePoint))
    {
        case Character.CONTROL:     // \p{Cc}
        case Character.FORMAT:      // \p{Cf}
        case Character.PRIVATE_USE: // \p{Co}
        case Character.SURROGATE:   // \p{Cs}
        case Character.UNASSIGNED:  // \p{Cn}
            newString.append('?');
            break;
        default:
            newString.append(Character.toChars(codePoint));
            break;
    }
}


4

实现目标的方法

public static String removeNonAscii(String str)
{
    return str.replaceAll("[^\\x00-\\x7F]", "");
}

public static String removeNonPrintable(String str) // All Control Char
{
    return str.replaceAll("[\\p{C}]", "");
}

public static String removeSomeControlChar(String str) // Some Control Char
{
    return str.replaceAll("[\\p{Cntrl}\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]", "");
}

public static String removeFullControlChar(String str)
{
    return removeNonPrintable(str).replaceAll("[\\r\\n\\t]", "");
} 

0

我为此使用了此简单功能:

private static Pattern pattern = Pattern.compile("[^ -~]");
private static String cleanTheText(String text) {
    Matcher matcher = pattern.matcher(text);
    if ( matcher.find() ) {
        text = text.replace(matcher.group(0), "");
    }
    return text;
}

希望这是有用的。


0

根据Op De Cirkelnoackjr的回答,以下是我做的常规字符串清理操作:1.修剪开头或结尾的空格,2.修改dos2unix,3. mac2unix,4.删除除空格以外的所有“不可见的Unicode字符”:

myString.trim.replaceAll("\r\n", "\n").replaceAll("\r", "\n").replaceAll("[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}&&[^\\s]]", "")

经过Scala REPL测试。


0

我建议它删除如下所示的不可打印字符,而不是替换它

private String removeNonBMPCharacters(final String input) {
    StringBuilder strBuilder = new StringBuilder();
    input.codePoints().forEach((i) -> {
        if (Character.isSupplementaryCodePoint(i)) {
            strBuilder.append("?");
        } else {
            strBuilder.append(Character.toChars(i));
        }
    });
    return strBuilder.toString();
}

-4

我已经重新设计了电话号码的代码+9(987)124124 从Java中的字符串中提取数字

 public static String stripNonDigitsV2( CharSequence input ) {
    if (input == null)
        return null;
    if ( input.length() == 0 )
        return "";

    char[] result = new char[input.length()];
    int cursor = 0;
    CharBuffer buffer = CharBuffer.wrap( input );
    int i=0;
    while ( i< buffer.length()  ) { //buffer.hasRemaining()
        char chr = buffer.get(i);
        if (chr=='u'){
            i=i+5;
            chr=buffer.get(i);
        }

        if ( chr > 39 && chr < 58 )
            result[cursor++] = chr;
        i=i+1;
    }

    return new String( result, 0, cursor );
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.