Come verificare se una stringa contiene solo ASCII?


120

La chiamata Character.isLetter(c)ritorna truese il carattere è una lettera. Ma c'è un modo per scoprire rapidamente se a Stringcontiene solo i caratteri di base di ASCII?

Risposte:


128

Da Guava 19.0 in poi, puoi usare:

boolean isAscii = CharMatcher.ascii().matchesAllOf(someString);

Questo utilizza il matchesAllOf(someString)metodo che si basa sul metodo factory ascii()piuttosto che sul ASCIIsingleton ormai deprecato .

Qui ASCII include tutti i caratteri ASCII inclusi i caratteri non stampabili inferiori a 0x20(spazio) come tabulazioni, line-feed / return ma anche BELcon codice 0x07e DELcon codice 0x7F.

Questo codice utilizza in modo non corretto i caratteri anziché i punti di codice, anche se i punti di codice sono indicati nei commenti delle versioni precedenti. Fortunatamente, i caratteri richiesti per creare un punto di codice con un valore pari U+010000o superiore a utilizzano due caratteri surrogati con un valore al di fuori dell'intervallo ASCII. Quindi il metodo riesce ancora a testare ASCII, anche per stringhe contenenti emoji.

Per le versioni precedenti di Guava senza il ascii()metodo puoi scrivere:

boolean isAscii = CharMatcher.ASCII.matchesAllOf(someString);

31
+1 Anche se va bene se non hai bisogno di un'altra libreria di terze parti, la risposta di Colin è molto più breve e molto più leggibile. Suggerire biblioteche di terze parti va perfettamente bene e non dovrebbe essere punito con un voto negativo.
Jesper

1
Devo anche sottolineare che CharMatcher sono davvero incredibilmente potenti e possono fare mooolto più di questo. Inoltre ci sono molti altri CharMatcher predefiniti oltre ad ASCII e ottimi metodi di fabbrica per la creazione di quelli personalizzati.
ColinD

7
CharMatcher.ASCIIè deprecato ora e sta per essere rimosso a giugno 2018.
thisarattr

108

Puoi farlo con java.nio.charset.Charset .

import java.nio.charset.Charset;

public class StringUtils {

  public static boolean isPureAscii(String v) {
    return Charset.forName("US-ASCII").newEncoder().canEncode(v);
    // or "ISO-8859-1" for ISO Latin 1
    // or StandardCharsets.US_ASCII with JDK1.7+
  }

  public static void main (String args[])
    throws Exception {

     String test = "Réal";
     System.out.println(test + " isPureAscii() : " + StringUtils.isPureAscii(test));
     test = "Real";
     System.out.println(test + " isPureAscii() : " + StringUtils.isPureAscii(test));

     /*
      * output :
      *   Réal isPureAscii() : false
      *   Real isPureAscii() : true
      */
  }
}

Rileva caratteri non ASCII in una stringa


10
Non penso sia una buona idea rendere il CharsetEncoder statico poiché secondo la documentazione "Le istanze di questa classe non sono sicure per l'uso da più thread simultanei".
pm_labs

@paul_sns, hai ragione CharsetEncoder non è thread-safe (ma Charset lo è) quindi non è una buona idea renderlo statico.
RealHowTo

11
Con Java 1.7 o versioni successive è possibile utilizzare al StandardCharsets.US_ASCIIposto di Charset.forName("US-ASCII").
Julian Lettner

Le soluzioni @RealHowTo Correct non dovrebbero fare affidamento sui commenti, preoccuparsi di risolvere questo problema e magari utilizzare un metodo oneliner basato su StandardCharsets? Potrei pubblicare un'altra risposta, ma preferisco correggere questa risposta molto apprezzata.
Maarten Bodewes

77

Ecco un altro modo che non dipende da una libreria ma utilizza un'espressione regolare.

Puoi usare questa singola riga:

text.matches("\\A\\p{ASCII}*\\z")

Intero programma di esempio:

public class Main {
    public static void main(String[] args) {
        char nonAscii = 0x00FF;
        String asciiText = "Hello";
        String nonAsciiText = "Buy: " + nonAscii;
        System.out.println(asciiText.matches("\\A\\p{ASCII}*\\z"));
        System.out.println(nonAsciiText.matches("\\A\\p{ASCII}*\\z"));
    }
}

15
\\ A - Inizio dell'inserimento ... \\ p {ASCII} * - Qualsiasi carattere ASCII ogni volta ... \\ z - Fine dell'inserimento
Arne Deutsch

@ArneDeutsch Ti dispiace se migliori la risposta e includo riferimenti a \P{Print}e \P{Graph}+ una descrizione? Perché hai bisogno di \Ae \z?
Maarten Bodewes

Cos'è quella regex? So che $ è la fine della stringa, ^ è l'inizio, mai sentito parlare di \\ A \\ p \\ z, potresti allegare il riferimento a javadoc?
deathangel908

@ deathangel908 \ A è l'inizio dell'input. \ z è la fine dell'input. ^ e $ si comportano diversamente in modalità MULTILINEA e DOTALL cambia il comportamento di \ A e \ z. Vedere stackoverflow.com/a/3652402/1003157
Raymond Naseef

58

Scorri la stringa e assicurati che tutti i caratteri abbiano un valore inferiore a 128.

Le stringhe Java sono concettualmente codificate come UTF-16. In UTF-16, il set di caratteri ASCII è codificato come i valori 0-127 e la codifica per qualsiasi carattere non ASCII (che può essere costituito da più di un carattere Java) è garantito per non includere i numeri 0-127


27
Con Java 1.8 puoi fare:str.chars().allMatch(c -> c < 128)
Julian Lettner

7
Se desideri caratteri stampabili, potresti voler testare c >= 0x20 && c < 0x7Fpoiché i primi 32 valori della codifica a 7 bit sono caratteri di controllo e il valore finale (0x7F) è DEL.
Maarten Bodewes

15

Oppure copia il codice dalla classe IDN .

// to check if a string only contains US-ASCII code point
//
private static boolean isAllASCII(String input) {
    boolean isASCII = true;
    for (int i = 0; i < input.length(); i++) {
        int c = input.charAt(i);
        if (c > 0x7F) {
            isASCII = false;
            break;
        }
    }
    return isASCII;
}

1
Funziona anche con unicode a 2 caratteri perché il primo carattere è> = U + D800
k3b

Ma nota che include caratteri non stampabili in ASCII (che è corretto, ma potrebbe non essere previsto). Ovviamente è possibile utilizzare direttamente return falseinvece di utilizzare isASCII = falsee break.
Maarten Bodewes

Questo è il codice di Oracle JDK. La copia potrebbe causare problemi legali.
Arne Deutsch

11

commons-lang3 di Apache contiene preziosi metodi di utilità / convenienza per tutti i tipi di "problemi", incluso questo.

System.out.println(StringUtils.isAsciiPrintable("!@£$%^&!@£$%^"));

1
Tieni presente che isAsciiPrintable restituisce false se la stringa contiene caratteri di tabulazione o avanzamento riga (\ t \ r \ n).
TampaHaze

@TampaHaze è perché internamente, controlla che ogni valore di carattere sia compreso tra 32 e 127. Penso che sia sbagliato. Dovremmo controllare da 0 a 127
therealprashant

1
@therealprashant se il nome del metodo fosse isAscii sarei d'accordo con te. Ma il metodo chiamato isAsciiPrintable implica che potrebbero aver escluso di proposito i caratteri da 0 a 31.
TampaHaze

4

prova questo:

for (char c: string.toCharArray()){
  if (((int)c)>127){
    return false;
  } 
}
return true;

"Prova questo" ottiene sempre un voto negativo. Che cosa significa questo fare ? Cosa è incluso e cosa no? Otterrei un voto negativo perché raddoppi anche la dimensione della memoria, a proposito.
Maarten Bodewes

1

Scorri la stringa e usa charAt () per ottenere il carattere. Quindi trattalo come un int e verifica se ha un valore Unicode (un superset di ASCII) che ti piace.

Rompi al primo che non ti piace.


1
private static boolean isASCII(String s) 
{
    for (int i = 0; i < s.length(); i++) 
        if (s.charAt(i) > 127) 
            return false;
    return true;
}

Risposta solo codice, si prega di indicare cosa fa, cioè che include caratteri non stampabili e un carattere non definito (0x7F) se si esegue questo controllo.
Maarten Bodewes

Questo potrebbe avermi morso dopo che il mio programma a lungo in esecuzione non è riuscito a trovare alcun personaggio di interesse. charAtrestituisce a char. Puoi testare direttamente se un tipo charè maggiore di un int senza prima convertirlo in un int o il tuo test esegue automaticamente la copertura? Forse puoi e forse lo fa? Sono andato avanti e convertito questo per un int in questo modo: if ((int)s.charAt(i) > 127). Non sono sicuro che i miei risultati siano diversi, ma mi sento meglio a lasciarlo correre. Vedremo: - \
harperville il

0

Era possibile. Bel problema.

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;

public class EncodingTest {

    static CharsetEncoder asciiEncoder = Charset.forName("US-ASCII")
            .newEncoder();

    public static void main(String[] args) {

        String testStr = "¤EÀsÆW°ê»Ú®i¶T¤¤¤ß3¼Ó®i¶TÆU2~~KITEC 3/F Rotunda 2";
        String[] strArr = testStr.split("~~", 2);
        int count = 0;
        boolean encodeFlag = false;

        do {
            encodeFlag = asciiEncoderTest(strArr[count]);
            System.out.println(encodeFlag);
            count++;
        } while (count < strArr.length);
    }

    public static boolean asciiEncoderTest(String test) {
        boolean encodeFlag = false;
        try {
            encodeFlag = asciiEncoder.canEncode(new String(test
                    .getBytes("ISO8859_1"), "BIG5"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return encodeFlag;
    }
}

0

Questo restituirà true se String contiene solo caratteri ASCII e false quando non lo contiene

Charset.forName("US-ASCII").newEncoder().canEncode(str)

Se vuoi rimuovere non ASCII, ecco lo snippet:

if(!Charset.forName("US-ASCII").newEncoder().canEncode(str)) {
                        str = str.replaceAll("[^\\p{ASCII}]", "");
                    }

-2
//return is uppercase or lowercase
public boolean isASCIILetter(char c) {
  return (c > 64 && c < 91) || (c > 96 && c < 123);
}

Un codice risponde solo con 4 magie e nessuna spiegazione di cosa fa . Per favore, aggiusta.
Maarten Bodewes
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.