Làm cách nào để kiểm tra nếu một Chuỗi chỉ chứa ASCII?


120

Cuộc gọi Character.isLetter(c)trở lại truenếu ký tự là một chữ cái. Nhưng có cách nào để nhanh chóng tìm ra nếu Stringchỉ chứa các ký tự cơ bản của ASCII không?

Câu trả lời:


128

Từ Guava 19.0 trở đi, bạn có thể sử dụng:

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

Điều này sử dụng matchesAllOf(someString)phương pháp dựa trên phương thức xuất xưởng ascii()thay vì ASCIIđơn lẻ hiện không dùng nữa .

Dưới đây ASCII bao gồm tất cả các ký tự ASCII bao gồm các ký tự không thể in được hạ thấp hơn 0x20(không gian) như tab, dòng thức ăn / lợi nhuận mà còn BELvới mã 0x07DELvới mã 0x7F.

Mã này sử dụng không chính xác các ký tự thay vì các điểm mã, ngay cả khi các điểm mã được chỉ định trong các nhận xét của các phiên bản trước đó. May mắn thay, các ký tự được yêu cầu để tạo điểm mã có giá trị bằng U+010000hoặc hơn sử dụng hai ký tự thay thế có giá trị nằm ngoài phạm vi ASCII. Vì vậy, phương pháp vẫn thành công trong việc thử nghiệm ASCII, ngay cả đối với các chuỗi có chứa biểu tượng cảm xúc.

Đối với các phiên bản Guava trước đó mà không có ascii()phương pháp bạn có thể viết:

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

31
+1 Mặc dù thật tốt nếu bạn không cần một thư viện bên thứ ba khác, câu trả lời của Colin ngắn hơn và dễ đọc hơn nhiều. Đề xuất thư viện của bên thứ ba là hoàn toàn OK và không nên bị trừng phạt bằng một phiếu bầu tiêu cực.
Jesper

1
Tôi cũng nên chỉ ra rằng CharMatchers thực sự vô cùng mạnh mẽ và có thể làm được nhiều hơn thế. Ngoài ra, còn có nhiều CharMatchers được xác định trước bên cạnh ASCII và các phương thức nhà máy tuyệt vời để tạo các tùy chỉnh.
ColinD

7
CharMatcher.ASCIIkhông được chấp nhận ngay bây giờ và sắp bị xóa vào tháng 6 năm 2018.
thisarattr

108

Bạn có thể làm điều đó với 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
      */
  }
}

Phát hiện ký tự không phải ASCII trong Chuỗi


10
Tôi không nghĩ rằng nên làm cho CharsetEncoder tĩnh vì theo tài liệu "Trường hợp của lớp này không an toàn để sử dụng bởi nhiều luồng đồng thời."
pm_labs

@paul_sns, bạn nói đúng CharsetEncoder không an toàn cho luồng (nhưng Charset là vậy) nên không nên để nó tĩnh.
RealHowTo

11
Với Java 1.7 trở lên, người ta có thể sử dụng StandardCharsets.US_ASCIIthay thế Charset.forName("US-ASCII").
Julian Lettner

@RealHowTo Các giải pháp chính xác không cần phải dựa vào nhận xét, quan tâm để khắc phục vấn đề này và có thể sử dụng phương pháp oneliner dựa trên StandardCharsets? Tôi có thể đăng một câu trả lời khác nhưng tôi muốn sửa câu trả lời được đánh giá cao này.
Maarten Bodewes

77

Đây là một cách khác không phụ thuộc vào thư viện mà sử dụng regex.

Bạn có thể sử dụng dòng duy nhất này:

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

Toàn bộ chương trình ví dụ:

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 - Bắt đầu nhập ... \\ p {ASCII} * - Bất kỳ ký tự ASCII nào bất cứ lúc nào ... \\ z - Kết thúc đầu vào
Arne Deutsch

@ArneDeutsch Bạn có phiền nếu tôi cải thiện câu trả lời và bao gồm các tham chiếu đến \P{Print}\P{Graph}+ một mô tả không? Tại sao bạn cần \A\z?
Maarten Bodewes

Regex đó là gì? Tôi biết rằng $ là kết thúc của chuỗi, ^ là bắt đầu, chưa bao giờ nghe nói về một trong hai \ A \\ p \\ z, bạn có thể vui lòng đính kèm tham chiếu đến javadoc không?
deathangel908

@ deathangel908 \ A là bắt đầu nhập. \ z là kết thúc của đầu vào. ^ và $ hành xử khác nhau trong chế độ MULTILINE và DOTALL thay đổi hành vi của \ A và \ z. Xem stackoverflow.com/a/3652402/1003157
Raymond Naseef

58

Lặp lại qua chuỗi và đảm bảo tất cả các ký tự có giá trị nhỏ hơn 128.

Chuỗi Java được mã hóa theo khái niệm là UTF-16. Trong UTF-16, bộ ký tự ASCII được mã hóa thành các giá trị 0 - 127 và mã hóa cho bất kỳ ký tự không phải ASCII nào (có thể bao gồm nhiều hơn một char Java) được đảm bảo không bao gồm các số 0 - 127


27
Với Java 1.8, bạn có thể làm:str.chars().allMatch(c -> c < 128)
Julian Lettner

7
Nếu bạn muốn các ký tự có thể in được, bạn có thể muốn kiểm tra vì c >= 0x20 && c < 0x7F32 giá trị đầu tiên của mã hóa 7 bit là các ký tự điều khiển và giá trị cuối cùng (0x7F) là DEL.
Maarten Bodewes

15

Hoặc bạn sao chép mã từ lớp 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
Điều này thậm chí hoạt động với 2-char-unicode vì 1st-char là> = U + D800
k3b

Nhưng lưu ý rằng nó bao gồm các ký tự không in được trong ASCII (điều này đúng, nhưng có thể không được mong đợi). Tất nhiên có thể sử dụng trực tiếp return falsethay vì sử dụng isASCII = falsebreak.
Maarten Bodewes

Đây là mã từ Oracle JDK. Sao chép có thể gây ra vấn đề pháp lý.
Arne Đức

11

commons-lang3 từ Apache chứa các phương thức tiện ích / tiện ích có giá trị cho tất cả các loại 'vấn đề', bao gồm cả phương pháp này.

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

1
Xin lưu ý rằng isAsciiPrintable trả về false nếu chuỗi chứa ký tự nguồn cấp dữ liệu tab hoặc dòng (\ t \ r \ n).
TampaHaze

@TampaHaze đó là vì trong nội bộ, việc kiểm tra mọi giá trị ký tự nằm trong khoảng từ 32 đến 127. Tôi nghĩ đó là sai. Chúng ta nên kiểm tra 0-127
therealprashant

1
@therealprashant nếu tên phương thức làAscii tôi sẽ đồng ý với bạn. Nhưng phương thức được đặt tên là isAsciiPrintable ngụ ý rằng họ có thể đã cố tình loại trừ các ký tự từ 0 đến 31.
TampaHaze

4

thử cái này:

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

"Hãy thử điều này" luôn nhận được một downvote. Cái này làm gì Những gì được bao gồm và những gì không? Nhân tiện, sẽ nhận được một downvote vì bạn tăng gấp đôi kích thước trong bộ nhớ.
Maarten Bodewes

1

Lặp lại qua chuỗi và sử dụng charAt () để lấy char. Sau đó coi nó như một int và xem nó có giá trị unicode (siêu bộ ASCII) mà bạn thích không.

Nghỉ lúc đầu bạn không thích.


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

Mã chỉ trả lời, vui lòng cho biết điều này làm gì, nghĩa là nó bao gồm các ký tự không in được và ký tự không xác định (0x7F) nếu bạn thực hiện kiểm tra này.
Maarten Bodewes

Điều này có thể có một chút cho tôi sau khi chương trình dài của tôi không tìm thấy bất kỳ nhân vật quan tâm. charAttrả về a char. Bạn có thể kiểm tra trực tiếp nếu một loại charlớn hơn int mà không chuyển đổi thành int, trước tiên, hoặc thử nghiệm của bạn có tự động thực hiện bao phủ không? Có lẽ bạn có thể và có thể nó không? Tôi đã đi trước và chuyển đổi nó thành một int như vậy : if ((int)s.charAt(i) > 127). Không chắc kết quả của tôi có khác đi không nhưng tôi cảm thấy tốt hơn khi để nó chạy. Chúng ta sẽ thấy: - \
harperville

0

Điều đó là có thể. Vấn đề khá.

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

Điều này sẽ trả về true nếu String chỉ chứa các ký tự ASCII và false khi nó không

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

Nếu bạn muốn xóa không phải ASCII, đây là đoạn trích:

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

Một mã chỉ trả lời với 4 phép thuật, và không có lời giải thích nó làm gì . Xin hãy điều chỉnh.
Maarten Bodewes
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.