【问题标题】:How to check if a String contains only ASCII?如何检查字符串是否仅包含 ASCII?
【发布时间】:2011-04-04 20:16:18
【问题描述】:

如果字符是字母,则调用 Character.isLetter(c) 返回 true。但是有没有办法快速找到String 是否只包含ASCII 的基本字符?

【问题讨论】:

    标签: java string character-encoding ascii


    【解决方案1】:

    这是另一种方法,不依赖于库,而是使用正则表达式。

    你可以使用这一行:

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

    理解正则表达式:

    • li \\A : 输入开始
    • \\p{ASCII} : 任意 ASCII 字符
    • *:所有重复
    • \\z:输入结束

    【讨论】:

    • \\A - 输入开始 ... \\p{ASCII}* - 任何时候的任何 ASCII 字符 ...\\z - 输入结束
    • @ArneDeutsch 你介意我改进答案并包含对\P{Print}\P{Graph} 的引用+ 描述吗?为什么需要\A\z
    • 那个正则表达式是什么?我知道 $ 是字符串的结尾,^ 是开始,从来没有听说过 \\A \\p \\z,你能附上对 javadoc 的引用吗?
    • @deathangel908 \A 是输入的开始。 \z 是输入的结尾。 ^ 和 $ 在 MULTILINE 模式下的行为不同,并且 DOTALL 改变 \A 和 \z 的行为。见stackoverflow.com/a/3652402/1003157
    【解决方案2】:

    在 Kotlin 中:

    fun String.isAsciiString() : Boolean =
        this.toCharArray().none { it < ' ' || it > '~' }
    

    【讨论】:

      【解决方案3】:

      在 Java 8 及更高版本中,可以将String#codePointsIntStream#allMatch 结合使用。

      boolean allASCII = str.codePoints().allMatch(c -> c < 128);
      

      【讨论】:

        【解决方案4】:

        如果 String 只包含 ASCII 字符则返回 true,否则返回 false

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

        如果你想删除非 ASCII ,这里是 sn-p:

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

        【讨论】:

        • Vanilla Java,简单易读,这个答案有什么不喜欢的?虽然,为了避免“US-ASCII”中的拼写错误:StandardCharsets.US_ASCII.newEncoder().canEncode(str)
        【解决方案5】:

        您可以使用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
              */
          }
        }
        

        Detect non-ASCII character in a String

        【讨论】:

        • 我不认为将 CharsetEncoder 设为静态是一个好主意,因为根据文档“此类的实例对于多个并发线程的使用是不安全的。”
        • @paul_sns,你说得对,CharsetEncoder 不是线程安全的(但 Charset 是),因此将其设为静态不是一个好主意。
        • Java 1.7 或更高版本可以使用StandardCharsets.US_ASCII 而不是Charset.forName("US-ASCII")
        • @RealHowTo 正确的解决方案不应该依赖 cmets,小心解决这个问题,也许使用基于 StandardCharsets 的 oneliner 方法?我可以发布另一个答案,但我宁愿修复这个高度赞赏的答案。
        【解决方案6】:

        Guava19.0 起,您可以使用:

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

        这使用了 matchesAllOf(someString) 方法,该方法依赖于工厂方法 ascii(),而不是现在已弃用的 ASCII 单例。

        这里 ASCII 包括所有 ASCII 字符包括低于0x20(空格)的不可打印字符,例如制表符、换行符/回车符,还有代码为0x07BELDEL 代码为0x7F

        此代码错误地使用字符而不是代码点,即使代码点在早期版本的 cmets 中指示。幸运的是,创建具有 U+010000 或更大值的代码点所需的字符使用两个具有 ASCII 范围之外的值的代理字符。所以该方法仍然可以成功地测试 ASCII,即使是包含表情符号的字符串。

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

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

        【讨论】:

        • +1 虽然不需要其他第三方库就很好,但 Colin 的回答更短且更具可读性。建议第三方库是完全可以的,不应以反对票来惩罚。
        • 我还应该指出,CharMatchers 确实非常强大,而且可以做的远不止这些。此外,除了 ASCII 之外,还有更多预定义的 CharMatchers,以及用于创建自定义的出色工厂方法。
        • CharMatcher.ASCII 现已弃用,将于 2018 年 6 月删除。
        【解决方案7】:
        private static boolean isASCII(String s) 
        {
            for (int i = 0; i < s.length(); i++) 
                if (s.charAt(i) > 127) 
                    return false;
            return true;
        }
        

        【讨论】:

        • 仅代码回答,请说明这是做什么的,即如果您执行此检查,它包括不可打印字符和未定义字符 (0x7F)。
        • 在我长时间运行的程序未能找到任何感兴趣的字符后,这可能会咬我。 charAt 返回 char。您是否可以直接测试类型 char 是否大于 int 而无需首先转换为 int,或者您的测试是否会自动进行覆盖?也许你可以,也许它可以?我继续将其转换为 int,如下所示:if ((int)s.charAt(i) &gt; 127)。不确定我的结果是否有任何不同,但让它运行我感觉更好。我们会看到:-\
        【解决方案8】:

        来自 Apache 的 commons-lang3 包含针对各种“问题”的有价值的实用程序/便利方法,包括这个问题。

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

        【讨论】:

        • 请注意,如果字符串包含制表符或换行符 (\t \r \n),isAsciiPrintable 返回 false。
        • @TampaHaze 那是因为在内部,它检查每个字符值是否在 32 到 127 之间。我认为那是错误的。我们应该检查从 0 到 127
        • @therealprashant 如果方法名称是 isAscii 我同意你的看法。但是被命名为 isAsciiPrintable 的方法意味着它们可能故意排除了字符 0 到 31。
        【解决方案9】:

        这是可能的。好问题。

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

        【讨论】:

          【解决方案10】:
          //return is uppercase or lowercase
          public boolean isASCIILetter(char c) {
            return (c > 64 && c < 91) || (c > 96 && c < 123);
          }
          

          【讨论】:

          • 一个代码只回答了 4 个魔法,没有解释它做了什么。请调整。
          【解决方案11】:

          试试这个:

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

          【讨论】:

          • “试试这个”总是被否决。这做什么?包括什么,不包括什么?顺便说一句,因为你的内存大小也增加了一倍,所以会被否决。
          【解决方案12】:

          或者你从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;
          }
          

          【讨论】:

          • 这甚至适用于 2-char-unicode,因为第一个字符 >= U+D800
          • 但请注意,它包含 ASCII 中的不可打印字符(这是正确的,但可能不是预期的)。当然可以直接使用return false,而不是使用isASCII = falsebreak
          • 这是来自 Oracle JDK 的代码。复制可能会导致法律问题。
          【解决方案13】:

          遍历字符串并确保所有字符的值都小于 128。

          Java 字符串在概念上被编码为 UTF-16。在 UTF-16 中,ASCII 字符集被编码为值 0 - 127,并且任何非 ASCII 字符(可能包含多个 Java 字符)的编码都保证不包含数字 0 - 127

          【讨论】:

          • 使用 Java 1.8 你可以做到:str.chars().allMatch(c -&gt; c &lt; 128)
          • 如果您想要可打印的字符,您可能需要测试 c &gt;= 0x20 &amp;&amp; c &lt; 0x7F,因为 7 位编码的前 32 个值是控制字符,最终值 (0x7F) 是 DEL
          【解决方案14】:

          遍历字符串,并使用 charAt() 获取字符。然后把它当作一个int,看看它是否有你喜欢的unicode值(ASCII的超集)。

          在你不喜欢的第一个休息。

          【讨论】:

            猜你喜欢
            • 2015-09-08
            • 1970-01-01
            • 1970-01-01
            • 2010-12-19
            • 2018-09-03
            • 2017-12-16
            • 1970-01-01
            • 2015-04-22
            相关资源
            最近更新 更多