正则表达式去除所有不可打印字符

8
我希望能从一个字符串中删除所有的不可打印ASCII字符,同时保留不可见字符。我认为这会奏效,因为空格、\n和\r是不可见字符但不是不可打印字符? 基本上,我得到了一个带有�字符的字节数组,我不希望它们存在于其中。所以我正在尝试将其转换为字符串,在再次将其用作字节数组之前删除�字符。现在我的代码可以正常处理空格,但\r和\n不能正常工作。应该使用什么正则表达式来保留它们?或者有比我做的更好的方法吗?
public void write(byte[] bytes, int offset, int count) {

    try {
        String str = new String(bytes, "ASCII");
        str2 = str.replaceAll("[^\\p{Print}\\t\\n]", "");
        GraphicsTerminalActivity.sendOverSerial(str2.getBytes("ASCII"));

    } catch (UnsupportedEncodingException e) {

        e.printStackTrace();
    }

     return;
 }

} 

编辑:我尝试了[^\x00-\x7F],这是ascii字符的范围...但是那些 � 符号仍然可以通过,很奇怪。


1
不要在正则表达式中使用 \t 和 \n。请正常使用 \t 和 \n,因为它们不是像 \w、\d、\s 这样的正则表达式字符类。 - Pshemo
1
这些字符可能不是不可打印的字符,而是(Unicode)字符,您的字体不支持。请提供一个示例字符串,可能还要通过 od -t u1 进行管道传输。 - Jens Erat
1
@Ranon 是的,我相信那些字符是Unicode字符,这是我收到的字符http://www.fileformat.info/info/unicode/char/fffd/index.htm。当我在终端仿真器中输入任何字符,例如g,我会得到一个字符串“g���\r\n”。因此,我想要删除�的出现。我认为代码是\uFFFd。我的语句正确地删除了它们,但我需要保留\r \n和\b。 - Paul
我发现java.lang.Character提供了所有所需的字符过滤功能。也许你根本不需要正则表达式。我已经为从Word用户复制到文本区域中的各种垃圾字符实现了一个字符过滤器,而且除了这个类之外什么都不需要。 - dkateros
FFFD是一个特殊的Unicode字符,代表无法在Unicode中编码的字符。你最好找出这些字符来自哪里,可能是其他地方出了问题... - Jens Erat
显示剩余3条评论
2个回答

14
以下正则表达式只匹配可打印文本。
[^\x00\x08\x0B\x0C\x0E-\x1F]*
以下正则表达式可查找非打印字符。
[\x00\x08\x0B\x0C\x0E-\x1F]

Java 代码:

boolean foundMatch = false;
try {
    Pattern regex = Pattern.compile("[\\x00\\x08\\x0B\\x0C\\x0E-\\x1F]");
    Matcher regexMatcher = regex.matcher(subjectString);
    foundMatch = regexMatcher.find();
    //Relace the found text with whatever you want
} catch (PatternSyntaxException ex) {
    // Syntax error in the regular expression
}

我需要一些非可打印字符,例如\r \n \b 来进行操作。但是我需要移除其他导致出现 � 的非可打印字符。例如 [^\x00-\x7F] 可以通过所有内容,但是 \p{print} 会阻止 \n \r \b 以及不正确的字符。 - Paul

1
我希望您提供一个更简单的解决方案。顺便提一下,您忽略了偏移量和计数。下面的解决方案将覆盖原始数组。
public void write(byte[] bytes, int offset, int count) {
    int writtenI = offset;
    for (int readI = offset; readI < offset + count; ++readI) {
        byte b = bytes[readI];
        if (32 <= b && b < 127) {
            // ASCII printable:
            bytes[writtenI] = bytes[readI]; // writtenI <= readI
            ++writtenI;
        }
    }
    byte[] bytes2 = new byte[writtenI - offset];
    System.arraycopy(bytes, offset, bytes2, 0, writtenI - offset);
    //String str = new String(bytes, offset, writtenI - offset, "ASCII");
    //bytes2 = str.getBytes("ASCII");
    GraphicsTerminalActivity.sendOverSerial(bytes2);
}

1
谢谢,我会尝试一下。不幸的是,我的测试电缆坏了,需要一周后才能尝试这个方法。当你说“// ASCII printable”时,你是指只有ASCII可打印字符吗?我需要一些非打印字符通过,比如\r \n \b。例如[^\x00-\x7F]允许所有内容通过,但\p{print}阻止\n \r \b,以及不正确的字符。所以对我而言,情况并不是忽略所有的非打印字符。 - Paul
1
你可以将它改为 0 <= b && b <= 127。或者由于byte是有符号的:b >= 0,并加上注释 // ASCII 7 bits range - Joop Eggen
是的,这样更好,但出现了一些“�”字符,我不知道为什么。我需要进行更多测试,看看哪个范围可以去除它们,哪个不能...谢谢。 - Paul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接