Wie überprüfe ich, ob ein String nur ASCII enthält?


120

Der Anruf wird Character.isLetter(c)zurückgegeben, truewenn das Zeichen ein Buchstabe ist. Aber gibt es eine Möglichkeit, schnell herauszufinden, ob a Stringnur die Basiszeichen von ASCII enthält?

Antworten:


128

Ab Guava 19.0 können Sie Folgendes verwenden:

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

Hierbei wird die matchesAllOf(someString)Methode verwendet, die auf der Factory-Methode ascii()und nicht auf dem jetzt veralteten ASCIISingleton basiert.

Hier enthält ASCII alle ASCII-Zeichen, einschließlich der nicht druckbaren Zeichen, die kleiner als 0x20(Leerzeichen) sind, wie Tabulatoren, Zeilenvorschub / Rückgabe, aber auch BELmit Code 0x07und DELmit Code 0x7F.

Dieser Code verwendet fälschlicherweise Zeichen anstelle von Codepunkten, selbst wenn Codepunkte in den Kommentaren früherer Versionen angegeben sind. Glücklicherweise verwenden die Zeichen, die zum Erstellen eines Codepunkts mit einem Wert von U+010000oder über erforderlich sind, zwei Ersatzzeichen mit einem Wert außerhalb des ASCII-Bereichs. Daher gelingt es der Methode immer noch, auf ASCII zu testen, selbst auf Zeichenfolgen, die Emojis enthalten.

Für frühere Guava-Versionen ohne die ascii()Methode können Sie schreiben:

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

31
+1 Obwohl es gut ist, wenn Sie keine andere Bibliothek eines Drittanbieters benötigen, ist Colins Antwort viel kürzer und viel lesbarer. Das Vorschlagen von Bibliotheken von Drittanbietern ist vollkommen in Ordnung und sollte nicht mit einer negativen Abstimmung bestraft werden.
Jesper

1
Ich sollte auch darauf hinweisen, dass CharMatchers wirklich unglaublich leistungsfähig sind und mehr als das können. Darüber hinaus gibt es neben ASCII noch viele weitere vordefinierte CharMatcher und großartige Factory-Methoden zum Erstellen benutzerdefinierter CharMatcher.
ColinD

7
CharMatcher.ASCIIist jetzt veraltet und wird im Juni 2018 entfernt.
thisarattr

108

Sie können dies mit java.nio.charset.Charset tun .

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

Erkennen Sie Nicht-ASCII-Zeichen in einem String


10
Ich halte es nicht für eine gute Idee, den CharsetEncoder statisch zu machen, da laut Dokumentation "Instanzen dieser Klasse für die Verwendung durch mehrere gleichzeitige Threads nicht sicher sind".
pm_labs

@paul_sns, Sie haben Recht. CharsetEncoder ist nicht threadsicher (Charset jedoch), daher ist es keine gute Idee, es statisch zu machen.
RealHowTo

11
Mit Java 1.7 oder höher kann man StandardCharsets.US_ASCIIstattdessen verwenden Charset.forName("US-ASCII").
Julian Lettner

@RealHowTo Richtige Lösungen sollten sich nicht auf Kommentare verlassen müssen, dieses Problem beheben und möglicherweise eine Oneliner-Methode verwenden, die auf StandardCharsets? Ich könnte eine andere Antwort posten, aber ich würde diese hoch geschätzte Antwort lieber korrigieren.
Maarten Bodewes

77

Hier ist eine andere Möglichkeit, die nicht von einer Bibliothek abhängt, sondern einen regulären Ausdruck verwendet.

Sie können diese einzelne Zeile verwenden:

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

Ganzes Beispielprogramm:

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 - Beginn der Eingabe ... \\ p {ASCII} * - Beliebiges ASCII-Zeichen jederzeit ... \\ z - Ende der Eingabe
Arne Deutsch

@ArneDeutsch Stört es Sie, wenn ich die Antwort verbessere und Verweise auf \P{Print}und \P{Graph}+ eine Beschreibung hinzufüge ? Warum brauchst du \Aund \z?
Maarten Bodewes

Was ist das für eine Regex? Ich weiß, dass $ das Ende der Zeichenfolge ist, ^ der Anfang ist, noch nie von \\ A \\ p \\ z gehört hat. Könnten Sie bitte den Verweis auf javadoc anhängen?
Deathangel908

@ deathangel908 \ A ist der Beginn der Eingabe. \ z ist das Ende der Eingabe. ^ und $ verhalten sich im MULTILINE-Modus unterschiedlich, und DOTALL ändert das Verhalten von \ A und \ z. Siehe stackoverflow.com/a/3652402/1003157
Raymond Naseef

58

Durchlaufen Sie die Zeichenfolge und stellen Sie sicher, dass alle Zeichen einen Wert von weniger als 128 haben.

Java-Strings werden konzeptionell als UTF-16 codiert. In UTF-16 wird der ASCII-Zeichensatz als die Werte 0 bis 127 codiert, und die Codierung für jedes Nicht-ASCII-Zeichen (das aus mehr als einem Java-Zeichen bestehen kann) enthält garantiert nicht die Zahlen 0 bis 127


27
Mit Java 1.8 können Sie:str.chars().allMatch(c -> c < 128)
Julian Lettner

7
Wenn Sie druckbare Zeichen möchten, möchten Sie möglicherweise testen, c >= 0x20 && c < 0x7Fda die ersten 32 Werte der 7-Bit-Codierung Steuerzeichen sind und der Endwert (0x7F) ist DEL.
Maarten Bodewes

15

Oder Sie kopieren den Code aus der IDN- Klasse.

// 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
Dies funktioniert sogar mit 2-Zeichen-Unicode, da das 1.
Zeichen

Beachten Sie jedoch, dass es nicht druckbare Zeichen in ASCII enthält (was korrekt ist, aber möglicherweise nicht erwartet wird). Es ist natürlich möglich, direkt zu verwenden, return falseanstatt isASCII = falseund zu verwenden break.
Maarten Bodewes

Dies ist Code aus Oracle JDK. Das Kopieren kann rechtliche Probleme verursachen.
Arne Deutsch

11

commons-lang3 von Apache enthält wertvolle Dienstprogramm- / Bequemlichkeitsmethoden für alle Arten von "Problemen", einschließlich dieser.

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

1
Beachten Sie, dass isAsciiPrintable false zurückgibt, wenn die Zeichenfolge Tabulator- oder Zeilenvorschubzeichen enthält (\ t \ r \ n).
TampaHaze

@TampaHaze das ist, weil intern überprüft wird, ob jeder Zeichenwert zwischen 32 und 127 liegt. Ich denke, das ist falsch. Wir sollten von 0 bis 127
therealprashant

1
@therealprashant Wenn der Methodenname isAscii wäre, würde ich Ihnen zustimmen. Die Methode mit dem Namen isAsciiPrintable impliziert jedoch, dass die Zeichen 0 bis 31 absichtlich ausgeschlossen wurden.
TampaHaze

4

Versuche dies:

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

"Try this" wird immer abgelehnt. Was hat das tun ? Was ist enthalten und was nicht? Würde eine Abwertung bekommen, weil du übrigens auch die Größe im Speicher verdoppelst.
Maarten Bodewes

1

Durchlaufen Sie die Zeichenfolge und verwenden Sie charAt (), um das Zeichen abzurufen. Behandeln Sie es dann als int und prüfen Sie, ob es einen Unicode-Wert (eine Obermenge von ASCII) hat, den Sie mögen.

Pause beim ersten, den du nicht magst.


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

Nur Code-Antwort, bitte geben Sie an, was dies bewirkt, dh dass es nicht druckbare Zeichen und ein undefiniertes Zeichen (0x7F) enthält, wenn Sie diese Prüfung durchführen.
Maarten Bodewes

Dieser hat mich vielleicht gebissen, nachdem mein langjähriges Programm keine interessierenden Charaktere gefunden hat. charAtgibt a zurück char. Können Sie direkt testen, ob ein Typ chargrößer als ein int ist, ohne zuerst in ein int zu konvertieren, oder führt Ihr Test die Coversion automatisch durch? Vielleicht kannst du und vielleicht tut es das? Ich ging voran und wandelte dies in ein int wie folgt um : if ((int)s.charAt(i) > 127). Ich bin mir nicht sicher, ob meine Ergebnisse anders sind, aber ich fühle mich besser, wenn ich es laufen lasse. Wir werden sehen: - \
Harperville

0

Es war möglich. Hübsches Problem.

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

Dies gibt true zurück, wenn String nur ASCII-Zeichen enthält, und false, wenn dies nicht der Fall ist

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

Wenn Sie Nicht-ASCII entfernen möchten, finden Sie hier das 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);
}

Ein Code antwortet nur mit 4 Magien und ohne Erklärung, was er tut . Bitte anpassen.
Maarten Bodewes
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.