Comment vérifier si une chaîne ne contient que de l'ASCII?

120

L'appel Character.isLetter(c)revient truesi le caractère est une lettre. Mais y a-t-il un moyen de trouver rapidement si a Stringne contient que les caractères de base de l'ASCII?

TambourinHomme
la source

Réponses:

128

À partir de Guava 19.0, vous pouvez utiliser:

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

Cela utilise la matchesAllOf(someString)méthode qui repose sur la méthode de fabrique ascii()plutôt que sur le ASCIIsingleton désormais obsolète .

Ici ASCII inclut tous les caractères ASCII y compris les caractères non imprimables inférieurs à 0x20(espace) tels que les tabulations, le saut de ligne / retour mais aussi BELavec code 0x07et DELavec code 0x7F.

Ce code utilise de manière incorrecte des caractères plutôt que des points de code, même si des points de code sont indiqués dans les commentaires des versions antérieures. Heureusement, les caractères requis pour créer un point de code avec une valeur de U+010000ou plus utilisent deux caractères de substitution avec une valeur en dehors de la plage ASCII. Ainsi, la méthode réussit toujours à tester l'ASCII, même pour les chaînes contenant des emoji.

Pour les versions antérieures de Guava sans la ascii()méthode, vous pouvez écrire:

boolean isAscii = CharMatcher.ASCII.matchesAllOf(someString);
ColinD
la source
31
+1 Bien que ce soit bien si vous n'avez pas besoin d'une autre bibliothèque tierce, la réponse de Colin est beaucoup plus courte et beaucoup plus lisible. Suggérer des bibliothèques tierces est parfaitement acceptable et ne devrait pas être sanctionné par un vote négatif.
Jesper
1
Je dois également souligner que les CharMatchers sont vraiment incroyablement puissants et peuvent faire beaucoup plus que cela. De plus, il existe beaucoup plus de CharMatchers prédéfinis en plus de l'ASCII, et d'excellentes méthodes d'usine pour créer des CharMatchers personnalisés.
ColinD
7
CharMatcher.ASCIIest obsolète maintenant et sur le point d'être supprimée en juin 2018.
thisarattr
108

Vous pouvez le faire avec 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
      */
  }
}

Détecter les caractères non ASCII dans une chaîne

RealHowTo
la source
10
Je ne pense pas que ce soit une bonne idée de rendre le CharsetEncoder statique puisque selon la documentation "Les instances de cette classe ne sont pas sûres pour une utilisation par plusieurs threads simultanés."
pm_labs
@paul_sns, vous avez raison CharsetEncoder n'est pas thread-safe (mais Charset l'est) donc ce n'est pas une bonne idée de le rendre statique.
RealHowTo
11
Avec Java 1.7 ou supérieur, on peut utiliser à la StandardCharsets.US_ASCIIplace de Charset.forName("US-ASCII").
Julian Lettner
@RealHowTo Les solutions correctes ne devraient pas avoir à se fier aux commentaires, prenez soin de résoudre ce problème et peut-être utiliser une méthode oneliner basée sur StandardCharsets? Je pourrais poster une autre réponse mais je préfère corriger cette réponse très appréciée.
Maarten Bodewes
77

Voici une autre façon de ne pas dépendre d'une bibliothèque mais d'utiliser une regex.

Vous pouvez utiliser cette seule ligne:

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

Exemple de programme complet:

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
la source
15
\\ A - Début de l'entrée ... \\ p {ASCII} * - N'importe quel caractère ASCII à tout moment ... \\ z - Fin de l'entrée
Arne Deutsch
@ArneDeutsch Cela vous dérange-t-il si j'améliore la réponse et que j'inclus des références à \P{Print}et \P{Graph}+ une description? Pourquoi avez-vous besoin \Aet \z?
Maarten Bodewes
Quelle est cette expression régulière? Je sais que $ est la fin de la chaîne, ^ est le début, jamais entendu parler de \\ A \\ p \\ z, pourriez-vous s'il vous plaît joindre la référence à javadoc?
deathangel908
@ deathangel908 \ A est le début de l'entrée. \ z est la fin de l'entrée. ^ et $ se comportent différemment en mode MULTILINE, et DOTALL change le comportement de \ A et \ z. Voir stackoverflow.com/a/3652402/1003157
Raymond Naseef le
58

Parcourez la chaîne et assurez-vous que tous les caractères ont une valeur inférieure à 128.

Les chaînes Java sont codées conceptuellement en UTF-16. En UTF-16, le jeu de caractères ASCII est codé comme les valeurs 0 à 127 et le codage de tout caractère non ASCII (qui peut être composé de plus d'un caractère Java) est garanti de ne pas inclure les nombres 0 à 127

JeremyP
la source
27
Avec Java 1.8, vous pouvez faire:str.chars().allMatch(c -> c < 128)
Julian Lettner
7
Si vous voulez des caractères imprimables, vous voudrez peut-être tester c >= 0x20 && c < 0x7Fcar les 32 premières valeurs du codage 7 bits sont des caractères de contrôle et la valeur finale (0x7F) est DEL.
Maarten Bodewes
15

Ou vous copiez le code de la 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;
}
Zarathoustra
la source
1
Cela fonctionne même avec 2-char-unicode car le 1er caractère est> = U + D800
k3b
Mais notez qu'il inclut des caractères non imprimables en ASCII (ce qui est correct, mais ce n'est peut-être pas prévu). Il est bien sûr possible d'utiliser directement return falseau lieu d'utiliser isASCII = falseet break.
Maarten Bodewes
Il s'agit du code d'Oracle JDK. La copie peut entraîner des problèmes juridiques.
Arne Deutsch
11

commons-lang3 d'Apache contient de précieuses méthodes utilitaires / pratiques pour toutes sortes de «problèmes», y compris celui-ci.

System.out.println(StringUtils.isAsciiPrintable("!@£$%^&!@£$%^"));
fjkjava
la source
1
Sachez que isAsciiPrintable renvoie false si la chaîne contient des tabulations ou des sauts de ligne (\ t \ r \ n).
TampaHaze
@TampaHaze c'est parce qu'en interne, il vérifie que chaque valeur de caractère est comprise entre 32 et 127. Je pense que c'est faux. Nous devrions vérifier de 0 à 127
therealprashant
1
@therealprashant si le nom de la méthode était isAscii, je serais d'accord avec vous. Mais la méthode nommée isAsciiPrintable implique qu'ils peuvent avoir délibérément exclu les caractères 0 à 31.
TampaHaze
4

essaye ça:

for (char c: string.toCharArray()){
  if (((int)c)>127){
    return false;
  } 
}
return true;
pforyogourt
la source
«Essayez ceci» reçoit toujours un vote défavorable. Qu'est-ce que cela fait ? Qu'est-ce qui est inclus et qu'est-ce qui ne l'est pas? J'obtiendrais un vote défavorable parce que vous doublez également la taille de la mémoire, au fait.
Maarten Bodewes
1

Parcourez la chaîne et utilisez charAt () pour obtenir le char. Traitez-le ensuite comme un entier et voyez s'il a une valeur unicode (un sur-ensemble d'ASCII) que vous aimez.

Pause au début que vous n'aimez pas.

Thorbjørn Ravn Andersen
la source
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
la source
Code seulement réponse, veuillez indiquer ce que cela fait, c'est-à-dire qu'il comprend des caractères non imprimables et un caractère non défini (0x7F) si vous effectuez cette vérification.
Maarten Bodewes
Celui-ci m'a peut-être mordu après que mon programme de longue date n'a pas réussi à trouver des caractères intéressants. charAtrenvoie un char. Pouvez-vous tester directement si un type charest supérieur à un int sans d'abord être converti en un int, ou votre test effectue-t-il automatiquement la conversion? Peut-être que vous pouvez et peut-être que oui? Je suis allé de l' avant et a converti ce à un int comme ceci: if ((int)s.charAt(i) > 127). Je ne sais pas si mes résultats sont différents, mais je me sens mieux de le laisser fonctionner. Nous verrons: - \
harperville le
0

C'était possible. Joli problème.

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;
    }
}
user3614583
la source
0

Cela renverra true si String ne contient que des caractères ASCII et false dans le cas contraire

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

Si vous souhaitez supprimer non ASCII, voici l'extrait de code:

if(!Charset.forName("US-ASCII").newEncoder().canEncode(str)) {
                        str = str.replaceAll("[^\\p{ASCII}]", "");
                    }
Mike oganyan
la source
-2
//return is uppercase or lowercase
public boolean isASCIILetter(char c) {
  return (c > 64 && c < 91) || (c > 96 && c < 123);
}
Lukas Greblikas
la source
Un code ne répond qu'avec 4 magies, et aucune explication de ce qu'il fait . Veuillez ajuster.
Maarten Bodewes