¿Cómo verificar si una cadena contiene solo ASCII?

120

La llamada Character.isLetter(c)regresa truesi el personaje es una letra. Pero, ¿hay alguna manera de encontrar rápidamente si a Stringsolo contiene los caracteres base de ASCII?

PanderetaHombre
fuente

Respuestas:

128

Desde Guava 19.0 en adelante, puede usar:

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

Esto utiliza el matchesAllOf(someString)método que se basa en el método de fábrica en ascii()lugar del ASCIIsingleton ahora obsoleto .

Aquí ASCII incluye todos los caracteres ASCII, incluidos los caracteres no imprimibles inferiores a 0x20(espacio) como tabulaciones, salto de línea / retorno, pero también BELcon código 0x07y DELcon código 0x7F.

Este código utiliza incorrectamente caracteres en lugar de puntos de código, incluso si los puntos de código se indican en los comentarios de versiones anteriores. Afortunadamente, los caracteres necesarios para crear un punto de código con un valor de U+010000o superior utilizan dos caracteres sustitutos con un valor fuera del rango ASCII. Entonces, el método aún tiene éxito en la prueba de ASCII, incluso para cadenas que contienen emoji.

Para versiones anteriores de Guava sin el ascii()método, puede escribir:

boolean isAscii = CharMatcher.ASCII.matchesAllOf(someString);
ColinD
fuente
31
+1 Aunque es bueno si no necesita otra biblioteca de terceros, la respuesta de Colin es mucho más corta y mucho más legible. Sugerir bibliotecas de terceros está perfectamente bien y no debe castigarse con un voto negativo.
Jesper
1
También debo señalar que CharMatchers son realmente increíblemente poderosos y pueden hacer mucho más que esto. Además, hay muchos más CharMatchers predefinidos además de ASCII, y excelentes métodos de fábrica para crear personalizados.
ColinD
7
CharMatcher.ASCIIestá en desuso ahora y a punto de eliminarse en junio de 2018.
thisarattr
108

Puede hacerlo 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
      */
  }
}

Detectar caracteres no ASCII en una cadena

RealHowTo
fuente
10
No creo que sea una buena idea hacer que CharsetEncoder sea estático ya que, según los documentos, "Las instancias de esta clase no son seguras para su uso por varios subprocesos simultáneos".
pm_labs
@paul_sns, tiene razón CharsetEncoder no es seguro para subprocesos (pero Charset sí lo es), por lo que no es una buena idea hacerlo estático.
RealHowTo
11
Con Java 1.7 o superior se puede usar en StandardCharsets.US_ASCIIlugar de Charset.forName("US-ASCII").
Julian Lettner
@RealHowTo Las soluciones correctas no deberían tener que depender de los comentarios, preocuparse por solucionar este problema y tal vez usar un método basado en un delineador StandardCharsets? Podría publicar otra respuesta, pero prefiero arreglar esta respuesta muy apreciada.
Maarten Bodewes
77

Aquí hay otra forma que no depende de una biblioteca, sino que usa una expresión regular.

Puede utilizar esta única línea:

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

Programa de ejemplo completo:

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"));
    }
}
Arne Deutsch
fuente
15
\\ A - Comienzo de la entrada ... \\ p {ASCII} * - Cualquier carácter ASCII en cualquier momento ... \\ z - Fin de la entrada
Arne Deutsch
@ArneDeutsch ¿Te importa si mejoro la respuesta e incluyo referencias \P{Print}y \P{Graph}+ una descripción? ¿Por qué necesitas \Ay \z?
Maarten Bodewes
¿Qué es esa expresión regular? Sé que $ es el final de la cadena, ^ es el inicio, nunca escuché de \\ A \\ p \\ z, ¿podría adjuntar la referencia a javadoc?
deathangel908
@ deathangel908 \ A es el inicio de la entrada. \ z es el final de la entrada. ^ y $ se comportan de manera diferente en el modo MULTILINE, y DOTALL cambia el comportamiento de \ A y \ z. Ver stackoverflow.com/a/3652402/1003157
Raymond Naseef
58

Repita la cadena y asegúrese de que todos los caracteres tengan un valor menor que 128.

Las cadenas de Java están codificadas conceptualmente como UTF-16. En UTF-16, el conjunto de caracteres ASCII se codifica con los valores 0-127 y se garantiza que la codificación de cualquier carácter no ASCII (que puede constar de más de un carácter Java) no incluye los números 0-127.

JeremyP
fuente
27
Con Java 1.8 puedes hacer:str.chars().allMatch(c -> c < 128)
Julian Lettner
7
Si desea caracteres imprimibles, es posible que desee probar, c >= 0x20 && c < 0x7Fya que los primeros 32 valores de la codificación de 7 bits son caracteres de control y el valor final (0x7F) es DEL.
Maarten Bodewes
15

O copia el código de la clase 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;
}
Zaratustra
fuente
1
Esto incluso funciona con 2-char-Unicode porque el 1st-char es> = U + D800
k3b
Pero tenga en cuenta que incluye caracteres no imprimibles en ASCII (lo cual es correcto, pero puede que no se espere). Por supuesto, es posible usar directamente en return falselugar de usar isASCII = falsey break.
Maarten Bodewes
Este es el código de Oracle JDK. La copia puede causar problemas legales.
Arne Deutsch
11

commons-lang3 de Apache contiene valiosos métodos de utilidad / conveniencia para todo tipo de "problemas", incluido este.

System.out.println(StringUtils.isAsciiPrintable("!@£$%^&!@£$%^"));
fjkjava
fuente
1
Tenga en cuenta que isAsciiPrintable devuelve falso si la cadena contiene caracteres de salto de línea o tabulación (\ t \ r \ n).
TampaHaze
@TampaHaze eso es porque internamente, está comprobando que cada valor de carácter esté entre 32 y 127. Creo que eso está mal. Debemos marcar de 0 a 127
therealprashant
1
@therealprashant si el nombre del método fuera isAscii, estaría de acuerdo contigo. Pero el método que se llama esAsciiPrintable implica que pueden haber excluido deliberadamente los caracteres del 0 al 31.
TampaHaze
4

prueba esto:

for (char c: string.toCharArray()){
  if (((int)c)>127){
    return false;
  } 
}
return true;
pforyogur
fuente
"Prueba esto" siempre recibe un voto negativo. ¿Qué tiene esto hacer ? ¿Qué está incluido y qué no? Por cierto, obtendría un voto negativo porque también duplica el tamaño de la memoria.
Maarten Bodewes
1

Repita la cadena y use charAt () para obtener el char. Luego trátelo como un int y vea si tiene un valor Unicode (un superconjunto de ASCII) que le guste.

Rompe a la primera que no te guste.

Thorbjørn Ravn Andersen
fuente
1
private static boolean isASCII(String s) 
{
    for (int i = 0; i < s.length(); i++) 
        if (s.charAt(i) > 127) 
            return false;
    return true;
}
fdsfdsfdsfds
fuente
Solo codifique la respuesta, indique lo que hace, es decir, que incluye caracteres no imprimibles y un carácter indefinido (0x7F) si realiza esta verificación.
Maarten Bodewes
Este puede haberme mordido después de que mi programa de larga duración no pudo encontrar ningún personaje de interés. charAtdevuelve un char. ¿Puedes probar directamente si un tipo chares mayor que un int sin convertirlo a un int, primero, o tu prueba hace la cobertura automáticamente? ¿Quizás puedas y quizás sí? Seguí adelante y convertido a un int este modo: if ((int)s.charAt(i) > 127). No estoy seguro de si mis resultados son diferentes, pero me siento mejor al dejarlo correr. Veremos: - \
harperville
0

Era posible. Bastante 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;
    }
}
usuario3614583
fuente
0

Esto devolverá verdadero si String solo contiene caracteres ASCII y falso cuando no los contiene

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

Si desea eliminar no ASCII, aquí está el fragmento:

if(!Charset.forName("US-ASCII").newEncoder().canEncode(str)) {
                        str = str.replaceAll("[^\\p{ASCII}]", "");
                    }
mike oganyan
fuente
-2
//return is uppercase or lowercase
public boolean isASCIILetter(char c) {
  return (c > 64 && c < 91) || (c > 96 && c < 123);
}
Lukas Greblikas
fuente
Un código solo responde con 4 magias, y sin explicación de lo que hace . Por favor, ajuste.
Maarten Bodewes