Como posso substituir caracteres Unicode não imprimíveis em Java?


88

O seguinte substituirá os caracteres de controle ASCII (abreviação de [\x00-\x1F\x7F]):

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

O seguinte substituirá todos os caracteres ASCII não imprimíveis (abreviação de [\p{Graph}\x20]), incluindo caracteres acentuados:

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

No entanto, nenhum dos dois funciona para strings Unicode. Alguém tem uma boa maneira de remover caracteres não imprimíveis de uma string Unicode?


2
Apenas como um adendo: a lista de categorias gerais Unicode pode ser encontrada em UAX # 44
— McDowell


1
@Stewart: oi, você olhou as perguntas / respostas além do título?!?
— dagnelies

1
@Stewart: essa outra questão cobre apenas o subconjunto ascii de caracteres não imprimíveis !!!
— dagnelies

Respostas:


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

Veja mais sobre Unicode regex . java.util.regexPattern/ os String.replaceAllapóia.


Pelo menos no java 1.6, não há suporte para eles. download.oracle.com/javase/6/docs/api/java/util/regex/… ... Eu também tentei sua linha, e além de não ter uma barra invertida, simplesmente não funciona.
— dagnelies 01 de

Isso funciona: char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?");também no javadoc para aparência de padrão na seção de suporte a Unicode , diz que suporta as categorias
— Op De Cirkel 01 de

Você está certo! Peço desculpas. Não percebi porque tive que adicionar as categorias Zl Zp, uma vez que essas eram principalmente a fonte dos problemas. Funciona perfeitamente. Você poderia fazer uma mini edição em sua postagem para que eu possa votar novamente?
— dagnelies 01 de

6
Existem também caracteres de espaço em branco invisíveis (como 0x0200B), que fazem parte do grupo \ p {Zs}. Infelizmente, este também inclui espaços em branco normais. Para aqueles que estão tentando filtrar uma string de entrada que não deve conter espaços, a string s.replaceAll("[\\p{C}\\p{Z}]", "")fará o encanto
— Andrey L

1
Isso é o que eu estava procurando, eu estava tentando, replaceAll("[^\\u0000-\\uFFFF]", "")mas não tive sucesso
— Bibaswann Bandyopadhyay

58

Op De Cirkel está quase certo. Sua sugestão funcionará na maioria dos casos:

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

Mas se myStringpode conter pontos de código não BMP, então é mais complicado. \p{C}contém os pontos de código substitutos de \p{Cs}. O método de substituição acima corromperá os pontos de código não BMP, às vezes substituindo apenas metade do par substituto. É possível que seja um bug do Java em vez do comportamento pretendido.

Usar as outras categorias constituintes é uma opção:

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

No entanto, personagens substitutos solitários que não fazem parte de um par (cada personagem substituto tem um ponto de código atribuído) não serão removidos. Uma abordagem não regex é a única maneira que conheço para lidar adequadamente com \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;
    }
}

8

Você pode estar interessado nas categorias Unicode "Outro, Controle" e possivelmente "Outro, Formato" (infelizmente o último parece conter caracteres não imprimíveis e imprimíveis).

Em expressões regulares Java, você pode verificá-las usando \p{Cc}e \p{Cf}respectivamente.


Bem, uma pena que as expressões java não os têm, mas pelo menos eu tenho a lista agora ... melhor do que nada. obrigado
— dagnelies

4

métodos em golpe para seu objetivo

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

Usei esta função simples para isso:

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;
}

Espero que isso seja útil.


0

Com base nas respostas de Op De Cirkel e noackjr , o seguinte é o que eu faço para limpeza geral de strings: 1. aparando espaços em branco iniciais ou finais, 2. dos2unix, 3. mac2unix, 4. removendo todos os "caracteres Unicode invisíveis", exceto espaços em branco:

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

Testado com Scala REPL.


0

Eu proponho remover os caracteres não imprimíveis como abaixo, em vez de substituí-los

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

Reestruturei o código para os números de telefone +9 (987) 124124 Extrai dígitos de uma string em 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 );
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.