【问题标题】:Java function to return if string contains illegal characters如果字符串包含非法字符,则返回 Java 函数
【发布时间】:2013-01-16 02:55:02
【问题描述】:

我希望将以下字符视为“非法”:

~, #, @, *, +, %, {, }, <, @987653331@, @98654331@, @9867653331@ 、|\_^

我想编写一个方法来检查字符串并确定 (true/false) 该字符串是否包含这些非法内容:

public boolean containsIllegals(String toExamine) {
    return toExamine.matches("^.*[~#@*+%{}<>[]|\"\\_^].*$");
}

但是,简单的matches(...) 检查对此并不可行。我需要该方法来扫描字符串中的每个字符并确保它不是这些字符之一。当然,我可以做一些可怕的事情,比如:

public boolean containsIllegals(String toExamine) {
    for(int i = 0; i < toExamine.length(); i++) {
        char c = toExamine.charAt(i);

        if(c == '~')
            return true;
        else if(c == '#')
            return true;

        // etc...
    }
}

有没有更优雅/更有效的方法来实现这一点?

【问题讨论】:

  • 为什么使用matches不可行?
  • 因为那不酷!

标签: java regex string


【解决方案1】:

您可以在这里使用PatternMatcher 类。您可以将所有过滤后的字符放在一个字符类中,并使用Matcher#find() 方法检查您的模式是否在字符串中可用。

你可以这样做:-

public boolean containsIllegals(String toExamine) {
    Pattern pattern = Pattern.compile("[~#@*+%{}<>\\[\\]|\"\\_^]");
    Matcher matcher = pattern.matcher(toExamine);
    return matcher.find();
}

find() 方法将返回 true,如果在字符串中找到给定的模式,即使是一次。


尚未指出的另一种方法是使用String#split(regex)。我们可以在给定的模式上拆分字符串,并检查数组的长度。如果长度为1,则该模式不在字符串中。

public boolean containsIllegals(String toExamine) {
    String[] arr = toExamine.split("[~#@*+%{}<>\\[\\]|\"\\_^]", 2);
    return arr.length > 1;
}

如果arr.length &gt; 1,这意味着字符串包含模式中的一个字符,这就是它被拆分的原因。我已将limit = 2 作为第二个参数传递给split,因为我们可以只进行一次拆分。

【讨论】:

  • 最干净和最好的解释。
  • 对于那些关注并且也被细节绊倒的人,请注意“matcher.find”使用较短的正则表达式,只有括号内的内容,但使用“matcher.matches”你会使用更长的表达式。只要使用正确的正则表达式,这两种技术都通过了我的单元测试。
【解决方案2】:

如果你不能使用匹配器,那么你可以做这样的事情,这比一堆不同的 if 语句或字节数组更干净。

 for(int i = 0; i < toExamine.length(); i++) {
    char c = toExamine.charAt(i);
    if("~#@*+%{}<>[]|\"_^".contains(c)){
         return true;
    }
 }

【讨论】:

    【解决方案3】:

    使用 constant 避免在每次验证中重新编译正则表达式。

    private static final Pattern INVALID_CHARS_PATTERN = 
                                   Pattern.compile("^.*[~#@*+%{}<>\\[\\]|\"\\_].*$");
    

    并将您的代码更改为:

    public boolean containsIllegals(String toExamine) {
        return INVALID_CHARS_PATTERN.matcher(toExamine).matches();
    }
    

    这是使用 Regex 最有效的方法。

    【讨论】:

      【解决方案4】:

      一种非常紧凑的方法是依赖String.replaceAll 方法:

      public boolean containsIllegal(final String toExamine) {
          return toExamine.length() != toExamine.replaceAll(
                  "[~#@*+%{}<>\\[\\]|\"\\_^]", "").length();
      }
      

      【讨论】:

        【解决方案5】:

        我需要扫描字符串中每个字符的方法

        如果您必须逐个字符地执行此操作,那么正则表达式可能不是一个好方法。但是,由于“黑名单”中的所有字符的代码都小于 128,因此您可以使用一个小的 boolean 数组:

        static final boolean blacklist[] = new boolean[128];
        
        static {
            // Unassigned elements of the array are set to false
            blacklist[(int)'~'] = true;
            blacklist[(int)'#'] = true;
            blacklist[(int)'@'] = true;
            blacklist[(int)'*'] = true;
            blacklist[(int)'+'] = true;
            ...
        }
        
        static isBad(char ch) {
            return (ch < 128) && blacklist[(int)ch];
        }
        

        【讨论】:

        • 如果我没记错的话,未初始化的布尔值在 Java 中会变成 false,不是吗?
        • @11684 正确 - boolean 数组的元素最初是 false
        • 也许这可能是答案的一部分,所以初学者也可以理解它?
        【解决方案6】:

        尝试否定包含所有列入黑名单的字符的字符类:

        public boolean containsIllegals(String toExamine) {
            return toExamine.matches("[^~#@*+%{}<>\\[\\]|\"\\_^]*");
        }
        

        如果字符串包含非法字符,这将返回 true(在这种情况下,您的原始函数似乎返回 false)。

        左括号[ 右侧的插入符号^ 否定字符类。请注意,在 String.matches() 中,您不需要锚点 ^$,因为它会自动匹配整个字符串。

        【讨论】:

          猜你喜欢
          • 2014-10-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-02
          • 2019-03-15
          相关资源
          最近更新 更多