如何检查字符串是否仅包含ASCII?


120

如果字符是字母,则呼叫Character.isLetter(c)返回true。但是,是否有一种方法可以快速查找a是否String仅包含ASCII的基本字符?

Answers:


128

Guava 19.0起,您可以使用:

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

这使用的matchesAllOf(someString)是依赖工厂方法的方法,ascii()而不是现在不推荐使用的ASCII单例方法。

此处ASCII包括所有ASCII字符,包括低于0x20(空格)的不可打印字符,例如制表符,换行/返回,还BEL包括带代码0x07DEL带代码0x7F

即使在早期版本的注释中指出了代码点,该代码也会错误地使用字符而不是代码点。幸运的是,创建值U+010000等于或大于的代码点所需的字符使用值在ASCII范围之外的两个替代字符。因此,该方法仍然可以成功测试ASCII,即使是包含表情符号的字符串。

对于没有该ascii()方法的早期Guava版本,您可以编写:

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

31
+1尽管不需要其他第三方库是很好的选择,但Colin的答案要短得多,可读性强。建议第三方库是完全可以的,不应以否决票受到惩罚。
杰斯珀,2010年

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 2012年

@paul_sns,您是正确的CharsetEncoder不是线程安全的(但Charset是线程安全的),因此使其静态化不是一个好主意。
RealHowTo 2012年

11
在Java 1.7或更高版本中,可以使用StandardCharsets.US_ASCII代替Charset.forName("US-ASCII")
朱利安·莱特纳2014年

@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 '19

@ 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因为7位编码的前32个值是控制字符,而最终值(0x7F)是DEL
Maarten Bodewes,2015年

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个字符的unicode,因为第1个字符> = U + D800
k3b

但请注意,它包括ASCII中不可打印的字符(这是正确的,但可能不期望)。当然可以直接使用return false而不是使用isASCII = falsebreak
Maarten Bodewes

这是来自Oracle JDK的代码。复制可能会导致法律问题。
Arne Deutsch

11

Apache的commons-lang3包含了有价值的实用程序/便利方法,可以解决各种“问题”,包括此问题。

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

1
请注意,如果字符串包含制表符或换行符(\ t \ r \ n),则isAsciiPrintable返回false。
TampaHaze

@TampaHaze多数民众赞成是因为在内部,它检查每个字符值在32到127之间。我认为那是错误的。我们应该检查从0到127
therealprashant

1
@therealprashant(如果方法名称为isAscii),我会同意你的看法。但名为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返回char。您是否可以直接测试类型char是否大于int而不先转换为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字符,则返回true,否则返回false。

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

如果您要删除非ASCII,请参见以下代码段:

if(!Charset.forName("US-ASCII").newEncoder().canEncode(str)) {
                        str = str.replaceAll("[^\\p{ASCII}]", "");
                    }

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.