Як перевірити, чи містить рядок лише ASCII?


120

Виклик Character.isLetter(c)повертається, trueякщо символом є буква. Але чи є спосіб швидко знайти, якщо Stringтільки в ньому є базові символи ASCII?

Відповіді:


128

З Guava 19.0 і далі ви можете використовувати:

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

Для цього використовується matchesAllOf(someString)метод, який спирається на заводський метод, ascii()а не на теперішній час застарілий ASCIIсинглтон.

Тут ASCII включає всі символи ASCII, включаючи символи, що не надруковані нижче 0x20(пробіл), такі як вкладки, подавання рядків / повернення, але також BELз кодом 0x07та DELкодом 0x7F.

Цей код неправильно використовує символи, а не кодові точки, навіть якщо кодові точки вказані в коментарях попередніх версій. На щастя, символи, необхідні для створення кодової точки зі значенням U+010000або більше, використовують два сурогатних символи зі значенням поза діапазоном ASCII. Таким чином, метод все ще вдається протестувати на ASCII, навіть для рядків, що містять смайли.

Для попередніх версій Guava без ascii()методу ви можете написати:

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

31
+1 Хоча це добре, якщо вам не потрібна інша стороння бібліотека, відповідь Коліна набагато коротша і значно читабельніша. Запропонувати сторонні бібліотеки цілком нормально, і не слід їх карати негативним голосом.
Jesper

1
Я також мушу зазначити, що CharMatchers справді неймовірно потужні і можуть зробити більше, ніж це. Окрім ASCII, існує ще багато заздалегідь визначених CharMatchers та чудові фабричні методи створення спеціальних.
ColinD

7
CharMatcher.ASCIIтепер застаріло і збирається видалити в червні 2018.
thisarattr

108

Ви можете зробити це за допомогою 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
      */
  }
}

Виявити символ, що не є ASCII, у рядку


10
Я не думаю, що це зробити гарну ідею стати CharsetEncoder статичним, оскільки згідно з документами "Екземпляри цього класу не є безпечними для використання у кількох одночасних потоках".
pm_labs

@paul_sns, ви праві, CharsetEncoder не є безпечним для потоків (але Charset є), тому не дуже добре робити його статичним.
RealHowTo

11
З Java 1.7 або вище можна використовувати StandardCharsets.US_ASCIIзамість Charset.forName("US-ASCII").
Джуліян Леттнер

@RealHowTo Правильні рішення не повинні покладатися на коментарі, намагайтеся виправити цю проблему і, можливо, використовувати метод oneliner на основі StandardCharsets? Я можу опублікувати ще одну відповідь, але я краще зафіксую цю високо оцінену відповідь.
Maarten Bodewes

77

Ось ще один спосіб не залежно від бібліотеки, а використання регулярного вираження.

Ви можете використовувати цей єдиний рядок:

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

Вся прикладна програма:

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 - Початок введення ... \\ p {ASCII} * - Будь-який символ ASCII будь-коли ... \\ z - Кінець введення
Arne Deutsch

@ArneDeutsch Ви заперечуєте, якщо я вдосконалюю відповідь і включатиму посилання на \P{Print}та \P{Graph}опис + Навіщо вам це потрібно \Aі \z?
Maarten Bodewes

Що це за регекс? Я знаю, що $ - це кінець рядка, ^ це початок, ніколи не чули жодного з \\ A \\ p \\ z, чи можете ви додайте посилання на javadoc?
deathangel908

@ deathangel908 \ A - це початок введення. \ z - кінець введення. ^ і $ поводяться по-різному в режимі MULTILINE, і DOTALL змінює поведінку \ A і \ z. Див stackoverflow.com/a/3652402/1003157
Raymond Naseef

58

Ітерайте через рядок і переконайтесь, що всі символи мають значення менше 128.

Струни Java концептуально кодуються як UTF-16. У UTF-16 набір символів ASCII кодується як значення 0 - 127, а кодування для будь-якого символу ASCII (який може складатися з декількох символів Java) гарантовано не включає цифри 0 - 127


27
З Java 1.8 ви можете:str.chars().allMatch(c -> c < 128)
Джуліан Леттнер

7
Якщо ви хочете друкувати символи, ви можете перевірити c >= 0x20 && c < 0x7F, що перші 32 значення 7-бітового кодування є контрольними символами, а кінцеве значення (0x7F) - це DEL.
Maarten Bodewes

15

Або ви скопіюєте код з класу 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
Це навіть працює з 2-char-unicode, оскільки 1-й символ> = U + D800
k3b

Але зауважте, що він включає недрукувальні символи в ASCII (що правильно, але цього можна не очікувати). Звичайно, можна безпосередньо використовувати return falseзамість isASCII = falseі break.
Maarten Bodewes

Це код від JDK Oracle. Копіювання може спричинити юридичні проблеми.
Арн Дойч

11

commons-lang3 від Apache містить цінні корисні / зручні методи для всіх видів «проблем», включаючи цю.

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

1
Будьте в курсі, що isAsciiPrintable повертає помилку, якщо рядок містить символи каналу вкладки або рядка (\ t \ r \ n).
TampaHaze

@TampaHaze це тому, що внутрішньо його перевірка на значення кожного символу становить від 32 до 127. Я думаю, що це неправильно. Ми повинні перевірити від 0 до 127
відпрацьовано

1
@therealprashant, якщо назва методу булаAscii, я б погодився з вами. Але метод, який називається isAsciiPrintable, означає, що вони, можливо, навмисно виключили символи від 0 до 31.
TampaHaze

4

спробуйте це:

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

"Спробуйте це" завжди отримує зворотний зв'язок. Що це робить ? Що включено, а що ні? Ви отримаєте зворотний зв'язок, оскільки, до речі, ви вдвічі збільшуєте розмір в пам'яті.
Maarten Bodewes

1

Ітерайте через рядок і використовуйте charAt (), щоб отримати char. Потім ставитесь до нього як до int і переконайтеся, що він має значення unicode (надмножина ASCII), яке вам подобається.

Перервіться спочатку, який вам не подобається.


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

Відповідь лише на код, будь ласка, вкажіть, що це робить, тобто що воно включає недруковані символи та невизначений символ (0x7F), якщо ви виконуєте цю перевірку.
Maarten Bodewes

Цей, можливо, мене покусав після того, як моя давно запущена програма не змогла знайти жодних персонажів, що цікавлять. charAtповертає a char. Чи можете ви безпосередньо перевірити, чи тип charбільше, ніж int, без перетворення спочатку на int, чи ваш тест автоматично робить покриття? Можливо, ти можеш, а може, і так? Я пішов вперед і перетворював це до міжнар так: if ((int)s.charAt(i) > 127). Не впевнений, чи відрізняються мої результати, але я краще почуваюсь, щоб дозволити її працювати. Ми побачимо: - \
harperville

0

Це було можливо. Досить проблема.

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

Це повернеться істинним, якщо String містить лише символи ASCII, а false - якщо немає

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

Якщо ви хочете видалити не ASCII, ось фрагмент:

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

Код відповідає лише чотирма магіями, і без пояснення, що це робить . Будь ласка, налаштуйте.
Maarten Bodewes
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.