Bagaimana cara memeriksa apakah sebuah String hanya berisi ASCII?


120

Panggilan akan Character.isLetter(c)kembali truejika karakternya adalah huruf. Tetapi adakah cara untuk mengetahui dengan cepat jika a Stringhanya berisi karakter dasar ASCII?

Jawaban:


128

Mulai Guava 19.0 dan seterusnya, Anda dapat menggunakan:

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

Ini menggunakan matchesAllOf(someString)metode yang bergantung pada metode pabrik ascii()daripada ASCIIsingleton yang sekarang tidak digunakan lagi .

Di sini ASCII menyertakan semua karakter ASCII termasuk karakter yang tidak dapat dicetak lebih rendah dari 0x20(spasi) seperti tab, line-feed / return tetapi juga BELdengan kode 0x07dan DELdengan kode 0x7F.

Kode ini salah menggunakan karakter daripada poin kode, meskipun poin kode ditunjukkan dalam komentar versi sebelumnya. Untungnya, karakter yang diperlukan untuk membuat titik kode dengan nilai lebih dari U+010000atau menggunakan dua karakter pengganti dengan nilai di luar rentang ASCII. Jadi metode ini masih berhasil menguji ASCII, bahkan untuk string yang berisi emoji.

Untuk versi Guava sebelumnya tanpa ascii()metode, Anda dapat menulis:

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

31
+1 Meskipun bagus jika Anda tidak memerlukan perpustakaan pihak ketiga lainnya, jawaban Colin jauh lebih singkat dan lebih mudah dibaca. Menyarankan perpustakaan pihak ketiga adalah baik-baik saja dan tidak boleh dihukum dengan suara negatif.
Jesper

1
Saya juga harus menunjukkan bahwa CharMatchers benar-benar sangat kuat dan dapat melakukan lebih dari ini. Selain itu, masih banyak lagi CharMatchers standar selain ASCII, dan metode pabrik yang bagus untuk membuat yang khusus.
ColinD

7
CharMatcher.ASCIIsudah usang sekarang dan akan dihapus pada Juni 2018.
thisarattr

108

Anda dapat melakukannya dengan 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
      */
  }
}

Mendeteksi karakter non-ASCII dalam String


10
Menurut saya bukan ide yang baik untuk membuat CharsetEncoder statis karena menurut dokumen "Instance kelas ini tidak aman untuk digunakan oleh beberapa thread bersamaan".
pm_labs

@paul_sns, Anda benar CharsetEncoder tidak aman untuk thread (tetapi Charset adalah) jadi bukan ide yang baik untuk membuatnya statis.
RealHowTo

11
Dengan Java 1.7 atau yang lebih baru dapat digunakan StandardCharsets.US_ASCIIsebagai pengganti Charset.forName("US-ASCII").
Julian Lettner

@RealHowTo Solusi yang benar tidak harus bergantung pada komentar, peduli untuk memperbaiki masalah ini dan mungkin menggunakan metode oneliner berdasarkan StandardCharsets? Saya dapat memposting jawaban lain tetapi saya lebih suka memperbaiki jawaban yang sangat dihargai ini.
Maarten Bodewes

77

Berikut adalah cara lain untuk tidak bergantung pada pustaka tetapi menggunakan regex.

Anda dapat menggunakan satu baris ini:

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

Seluruh program contoh:

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 - Awal masukan ... \\ p {ASCII} * - Semua karakter ASCII kapan saja ... \\ z - Akhir masukan
Arne Deutsch

@ArneDeutsch Apakah Anda keberatan jika saya meningkatkan jawaban dan menyertakan referensi ke \P{Print}dan \P{Graph}+ deskripsi? Mengapa Anda membutuhkan \Adan \z?
Maarten Bodewes

Apa regex itu? Saya tahu bahwa $ adalah akhir string, ^ dimulai, tidak pernah mendengar salah satu dari \\ A \\ p \\ z, bisakah Anda melampirkan referensi ke javadoc?
deathangel908

@ deathangel908 \ A adalah awal dari input. \ z adalah akhir masukan. ^ dan $ berperilaku berbeda dalam mode MULTILINE, dan DOTALL mengubah perilaku \ A dan \ z. Lihat stackoverflow.com/a/3652402/1003157
Raymond Naseef

58

Iterasi melalui string dan pastikan semua karakter memiliki nilai kurang dari 128.

String Java secara konseptual dikodekan sebagai UTF-16. Dalam UTF-16, kumpulan karakter ASCII dikodekan sebagai nilai 0 - 127 dan pengkodean untuk setiap karakter non ASCII (yang mungkin terdiri dari lebih dari satu karakter Java) dijamin tidak menyertakan angka 0 - 127


27
Dengan Java 1.8 Anda dapat melakukan:str.chars().allMatch(c -> c < 128)
Julian Lettner

7
Jika Anda menginginkan karakter yang dapat dicetak, Anda mungkin ingin menguji karena c >= 0x20 && c < 0x7F32 nilai pertama dari pengkodean 7 bit adalah karakter kontrol dan nilai akhir (0x7F) adalah DEL.
Maarten Bodewes

15

Atau Anda menyalin kode dari kelas 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
Ini bahkan berfungsi dengan 2-char-unicode karena karakter pertama adalah> = U + D800
k3b

Tetapi perhatikan bahwa itu termasuk karakter yang tidak dapat dicetak dalam ASCII (yang benar, tetapi mungkin tidak diharapkan). Tentu saja mungkin untuk langsung menggunakan return falsedaripada menggunakan isASCII = falsedan break.
Maarten Bodewes

Ini adalah kode dari Oracle JDK. Menyalin dapat menyebabkan masalah hukum.
Arne Deutsch

11

commons-lang3 dari Apache berisi metode utilitas / kenyamanan yang berharga untuk semua jenis 'masalah', termasuk yang ini.

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

1
Ketahuilah bahwa isAsciiPrintable mengembalikan false jika string berisi karakter tab atau feed baris (\ t \ r \ n).
TampaHaze

@TampaHaze itu karena secara internal, pemeriksaan untuk setiap nilai karakter antara 32 hingga 127. Saya pikir itu salah. Kita harus memeriksa dari 0 hingga 127
prashant

1
@ therealprashant jika nama metode adalah isAscii Saya setuju dengan Anda. Tetapi metode yang dinamai isAsciiPrintable menyiratkan bahwa mereka mungkin sengaja mengecualikan karakter 0 hingga 31.
TampaHaze

4

coba ini:

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

"Coba ini" selalu mendapat suara negatif. Apa ini lakukan ? Apa yang termasuk dan apa yang tidak? Akan mendapat downvote karena Anda menggandakan ukuran dalam memori juga.
Maarten Bodewes

1

Iterasi melalui string, dan gunakan charAt () untuk mendapatkan karakter. Kemudian perlakukan itu sebagai int, dan lihat apakah itu memiliki nilai unicode (superset dari ASCII) yang Anda suka.

Istirahat dulu yang tidak Anda sukai.


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

Kode hanya menjawab, tunjukkan apa yang dilakukannya, yaitu menyertakan karakter yang tidak dapat dicetak dan karakter yang tidak ditentukan (0x7F) jika Anda melakukan pemeriksaan ini.
Maarten Bodewes

Yang ini mungkin telah menggigit saya setelah program saya yang berjalan lama gagal menemukan karakter yang menarik. charAtmengembalikan a char. Dapatkah Anda langsung menguji jika suatu tipe charlebih besar dari int tanpa mengonversi ke int, pertama, atau apakah pengujian Anda secara otomatis melakukan penutup? Mungkin Anda bisa dan mungkin bisa? Aku pergi ke depan dan dikonversi ini ke int seperti: if ((int)s.charAt(i) > 127). Tidak yakin apakah hasil saya berbeda tetapi saya merasa lebih baik untuk membiarkannya berjalan. Kita akan lihat: - \
harperville

0

Itu mungkin saja. Masalah yang lumayan.

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

Ini akan mengembalikan nilai true jika String hanya berisi karakter ASCII dan false jika tidak

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

Jika Anda ingin menghapus non ASCII, berikut cuplikannya:

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

Kode hanya menjawab dengan 4 sihir, dan tidak ada penjelasan apa yang dilakukannya . Harap sesuaikan.
Maarten Bodewes
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.