【问题标题】:Is there a way to specify a Regex which doesn't match any of the others?有没有办法指定一个不匹配任何其他正则表达式?
【发布时间】:2016-09-15 08:42:13
【问题描述】:

假设我有这样的事情:

    pattern = new Pattern[6];
    pattern[0] = Pattern.compile("^\\s*(NAME\\:\\s*)\\s(\\w+)");
    pattern[1] = Pattern.compile("^\\s*(AGE\\:\\s*)\\s(\\d+)");
    pattern[2] = Pattern.compile("^\\s*(ADDRESS\\:\\s)(\\w+)");
    pattern[3] = Pattern.compile("^\\s*(BIRTHDAY\\:\\s)(\\d+)\\:(\\d+)\\:(\\d+)");        
    pattern[4] = Pattern.compile("(?=\\s*\\*)(^\\**)");
    pattern[5] = Pattern.compile("\\S+|[^\\s*.+\\s*]");

模式 4 的要点是捕获后跟 * 的 cmets,模式 5 是捕获其他模式无法捕获的所有其他内容。然后 Matcher dp 将检查该模式是否是 LookAhead 预期返回 true 或 false 的模式。

    public boolean lookAhead () {
        while ((line = buff.readLine()) != null) {
                 Pattern different = Pattern.compile("^[^(\\s*NAME.*)(\\s*AGE.*)(\\s*ADDRESS.*)(\\s*BIRTHDAY.*)]");                
                 Matcher comment = pattern[4].matcher(line);
                 Matcher diff = different.matcher(line);
                 Matcher name = pattern[0].matcher(line);
                 if (comment.find() || different.find() /*|| name.find()*/)               
                     continue;
                    Matcher dp = pattern[0].matcher(line);
                    dpla = dp.find();
                    break;
                 }
        }
        return dpla;
     }

cmets 会被忽略,并且所有随机错误(例如:“feifiejfie”)也会被忽略。但是,如果文本类似于“NAME 7987997 GSGSGE 456”,则应将其视为错误,但事实并非如此。如果 name.find 未注释,它将始终有效,但它永远不会返回 false。

【问题讨论】:

  • 也许您还应该说出您输入的有效变体是什么样的;以及您的代码实际上应该做什么。我很难从您的正则表达式中扣除该逻辑。这已经稍微暗示了您当前的代码可能不太容易阅读。含义:我认为这里的解决方案是通过专注于你真正想知道的关于你的输入的事情来大幅修改你的代码。因此:请说明您的要求。
  • pattern[4] 在我看来是错误的。它匹配“输入开始时的一个或多个星号”,并且大多数向前看是没有意义的;相当于"^\\*+"
  • 备案:如果我的回答对你有帮助,请告诉我;或者如果缺少某些东西......
  • @GhostCat 是的,谢谢你的回复,你的想法似乎很不错,但是我现在做了这么多,我需要很长时间来重组所有东西,我是几个小时前能够得到我自己问题的答案,请随时查看并告诉我您的想法,但我一定会牢记您对未来项目的想法。

标签: java regex


【解决方案1】:

让我们简单地采用一些不同的方法。我认为,本质上,您有一些输入字符串;然后你有一个不同的正则表达式列表,这些正则表达式可能包含你感兴趣的匹配器。你在代码中做了很多匹配,最终只返回一个布尔值;这似乎没有用;所以我要告诉你如何以不同的方式做事。

 class RegexListMatcher {
   private final Map<String, Pattern> patternsById;
   private final String inputToMatchOn;

   private final String matchingId;
   private final String matchResult;

   RegexListMatcher(Map<String, Pattern> patternsById, inputToMatchOn) {
     this.patterns... = patterns
     this.input... = input

     matchingId = findMatchingId();
     if (matchingId == null) {
        matchResult = null;
     } else {
        matchResult = getMatchResult();
     }
   }

   private final String findMatchingId() {
     for (Entry<String, Pattern> entry : patternsById) {
       if entry.value matches the given input return entry.key

     otherwise return null
   }

   private final String getMatchResult() {
     Pattern pattern = patternsById.get(matchingId);
     return the value matched within input 
   }

   public boolean hasMatch() { return matchingID != null; }
   public String getMatchId() ...
   public String getMatchResult() ...

用法如下:

 private final static Map<String, Pattern> RULES = new HashMap<>();
 RULES.put("NAME", Pattern.compile("^\\s*(NAME\\:\\s*)\\s(\\w+)"));
 ...

 RegexListMatcher listMatcher = new RegexListMatcher(RULES, someInputString);
 if (listMatcher.hasMatch()) { 
   one of the rules matched
 } else {
   no match at all
 }

我实现的关键点:你有一个潜在模式的列表;如果其中之一匹配,您肯定会对输入中匹配的值感兴趣。令人惊讶的是:如果没有一个模式匹配,那么你也知道这一点。因为 RegexListMatcher 可以告诉你。

当然,比你的代码更多;但例如:根本没有对某个数组索引的任何硬编码访问。显然,上面是部分伪代码,但我想它应该足以让你开始。

【讨论】:

    【解决方案2】:

    我今天能够解决问题!如果我没有很好地解释我的问题,我很抱歉,因为我必须编写更简单的正则表达式来尝试解释问题,也许我错过了一些重要的点来得到一个好的答案。与我所拥有的相比,这是一段非常简化的代码。主要问题是,如果模式以 NAME: 或 AGE 开头,尽管 cmets 和不是模式的所有内容(模式“错误”否定以其他模式开头的所有内容)都会被检测到并继续 While 循环: 等等,这意味着它将与“错误”模式不同,因此它不会继续循环,但是这不应该发生,因为它应该只在检测到有效模式时才停止循环。所以我做的是这样的:

    Pattern legit = Pattern.compile("^[(\\s*NAME.*)(\\s*AGE.*)(\\s*ADDRESS.*)(\\s*BIRTHDAY.*)");
    Matcher leg = legit.matcher(line);
    

    此模式的要点是确定在注释和错误失败的情况下可能发生的情况。如果他们这样做了,他们需要检查有效的是否失败:

    (leg.find() && (!name.find() && !age.find() && !addr.find() && !bd.find())))
    

    你可以通过参数处的int选择你想找到的模式,它会改变这个:

    Matcher input = pattern[a].matcher(line);
                     if (!input.find() ...)
    

    所以所有的组合都会是这样的:

    public boolean lookAhead (int a) {
            Pattern error = Pattern.compile("^[^(\\s*NAME.*)(\\s*AGE.*)(\\s*ADDRESS.*)(\\s*BIRTHDAY.*)]");
            Pattern legit = Pattern.compile("^[(\\s*NAME.*)(\\s*AGE.*)(\\s*ADDRESS.*)(\\s*BIRTHDAY.*)");
            while ((line = buff.readLine()) != null) {                                
                     Matcher comment = pattern[4].matcher(line);
                     Matcher err = error.matcher(line);
                     Matcher leg = legit.matcher(line);
                     Matcher name = pattern[0].matcher(line);
                     Matcher age = pattern[1].matcher(line);
                     Matcher addr = pattern[2].matcher(line);
                     Matcher bd = pattern[3].matcher(line);
                     Matcher input = pattern[a].matcher(line);
                     if (!input.find() && (comment.find() || err.find() || (leg.find() && (!name.find() && !age.find() && !addr.find() && !bd.find())))               
                         continue;
                        Matcher dp = pattern[a].matcher(line);
                        dpla = dp.find();
                        break;
                     }
            }
            return dpla;
         }
    

    完全按照我的意愿工作 :D

    【讨论】:

      猜你喜欢
      • 2012-11-22
      • 1970-01-01
      • 2019-02-11
      • 1970-01-01
      • 2017-10-27
      • 2022-01-13
      • 2013-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多