【问题标题】:Remove non-ASCII non-printable characters from a String从字符串中删除非 ASCII 不可打印字符
【发布时间】:2012-06-16 18:22:42
【问题描述】:

我得到的用户输入包括非 ASCII 字符和不可打印字符,例如

\xc2d
\xa0
\xe7
\xc3\ufffdd
\xc3\ufffdd
\xc2\xa0
\xc3\xa7
\xa0\xa0

例如:

email : abc@gmail.com\xa0\xa0
street : 123 Main St.\xc2\xa0

想要的输出:

  email : abc@gmail.com
  street : 123 Main St.

使用 Java 删除它们的最佳方法是什么?
我尝试了以下方法,但似乎不起作用

public static void main(String args[]) throws UnsupportedEncodingException {
        String s = "abc@gmail\\xe9.com";
        String email = "abc@gmail.com\\xa0\\xa0";

        System.out.println(s.replaceAll("\\P{Print}", ""));
        System.out.println(email.replaceAll("\\P{Print}", ""));
    }

输出

abc@gmail\xe9.com
abc@gmail.com\xa0\xa0

【问题讨论】:

  • 为什么要删除它们?
  • @jtahlborn,Mongo 无法序列化这些值
  • @daydreamer [需要引用] \xc2d 是一个有效的 Unicode 字符。如果 MongoDB 使用 UTF-8 应该能够序列化它们。也许你在这里有一个 XY 问题?你是如何序列化你的文本的?

标签: java non-ascii-characters


【解决方案1】:

您的要求不明确。 Java String 中的所有字符都是 Unicode 字符,因此如果您删除它们,您将得到一个空字符串。我假设您的意思是要删除任何非 ASCII、不可打印的字符。

String clean = str.replaceAll("\\P{Print}", "");

这里,\p{Print}represents a POSIX character class 用于可打印的 ASCII 字符,而\P{Print} 是该类的补充。使用此表达式,所有 不可 可打印的 ASCII 字符都将替换为空字符串。 (额外的反斜杠是因为\ 在字符串文字中开始了转义序列。)


显然,所有输入的字符实际上都是 ASCII 字符,代表不可打印或非 ASCII 字符的可打印编码。 Mongo 对这些字符串应该没有任何问题,因为它们只包含纯可打印的 ASCII 字符。

这对我来说听起来有点可疑。我认为正在发生的事情是数据确实包含不可打印和非 ASCII 字符,而另一个组件(如日志框架)正在用可打印的表示替换这些。在您的简单测试中,您未能将可打印表示转换回原始字符串,因此您错误地认为第一个正则表达式不起作用。

这是我的猜测,但如果我误读了情况并且您确实需要去除文字 \xHH 转义,您可以使用以下正则表达式来做到这一点。

String clean = str.replaceAll("\\\\x\\p{XDigit}{2}", "");

Pattern 类的 API 文档很好地列出了 Java 正则表达式库支持的所有语法。要详细了解所有语法的含义,我发现Regular-Expressions.info site 非常有帮助。

【讨论】:

  • 这不起作用。可能是我做错了什么,但没有工作
  • @daydreamer 你能提供一个SSCCE 来显示什么不工作吗?
  • public static void main(String args[]) throws UnsupportedEncodingException { String s = "abc@gmail\\xe9.com";字符串电子邮件 = "abc@gmail.com\\xa0\\xa0"; System.out.println(s.replaceAll("\\P{Print}", "")); System.out.println(email.replaceAll("\\P{Print}", "")); } 输出 - abc@gmail\xe9.com abc@gmail.com\xa0\xa0
  • @daydreamer \\x 在 Java 源代码中没有任何特别之处。 Stringchar 文字中的 \\ 是用 \ 替换的转义序列。如果您想要 Unicode 转义,请使用 \uXXXX,其中 XXXX 是 Unicode 点,以十六进制表示。
  • @daydreamer 例如String s = "abc@gmail\u00e9.com";
【解决方案2】:

使用Google GuavaCharMatcher,您可以删除任何non-printable 字符,然后保留所有ASCII 字符(删除任何重音符号),如下所示:

String printable = CharMatcher.INVISIBLE.removeFrom(input);
String clean = CharMatcher.ASCII.retainFrom(printable);

不确定这是否是您真正想要的,但它会删除问题示例数据中以转义序列表示的任何内容。

【讨论】:

  • 注意,INVISIBLE 删除了我觉得奇怪的空白,因为它确实是“可打印的”
【解决方案3】:

我知道可能有点晚了,但供将来参考:

String clean = str.replaceAll("\\P{Print}", "");

删除所有不可打印的字符,但包括\n(换行)、\t(制表符)和@​​987654324@(回车),有时您希望保留这些字符。

对于这个问题,使用倒置逻辑:

String clean = str.replaceAll("[^\\n\\r\\t\\p{Print}]", "");

【讨论】:

  • 赞成它在 mongo-land 中特别有用,以防止外壳喷出大量编码的非 ascii 内容(如果你想让事情变得简单,mongo 真的更喜欢 utf-8)跨度>
  • 得到错误:非法转义字符 String clean = str.replaceAll("[^\n\r\t\p{Print}]", ""); . \p 应该是 \P
  • 真的帮了我很多谢谢@Ivan
【解决方案4】:

你可以试试这个代码:

public String cleanInvalidCharacters(String in) {
    StringBuilder out = new StringBuilder();
    char current;
    if (in == null || ("".equals(in))) {
        return "";
    }
    for (int i = 0; i < in.length(); i++) {
        current = in.charAt(i);
        if ((current == 0x9)
                || (current == 0xA)
                || (current == 0xD)
                || ((current >= 0x20) && (current <= 0xD7FF))
                || ((current >= 0xE000) && (current <= 0xFFFD))
                || ((current >= 0x10000) && (current <= 0x10FFFF))) {
            out.append(current);
        }

    }
    return out.toString().replaceAll("\\s", " ");
}

我可以从String 中删除无效字符。

【讨论】:

  • 这是很多神奇的数字。如何将这些子句(尤其是范围)提取到恰当命名的局部变量中?
【解决方案5】:

你可以使用 java.text.normalizer

【讨论】:

    【解决方案6】:

    Input => "这个 \u7279文本 \u7279是我需要的" Output => "这就是我需要的文本"

    如果您尝试从上述字符串中删除 Unicode 字符,则此代码将起作用

    Pattern unicodeCharsPattern = Pattern.compile("\\\\u(\\p{XDigit}{4})");
    Matcher unicodeMatcher = unicodeChars.matcher(data);
    String cleanData = null;
    if (unicodeMatcher.find()) {
        cleanData = unicodeMatcher.replaceAll("");
    }
    

    【讨论】: