【问题标题】:Find match String using java regular expression with criteria使用带有条件的java正则表达式查找匹配字符串
【发布时间】:2022-02-03 11:57:04
【问题描述】:

在 Java 中 考虑一下字符串列表,随机出现一个具有不同值的字符串。

"59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee-1km(mm/hr)" OR
"59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee" OR
"59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y" OR
"59USD-300kg-25mb_4G-48p/min(Incl. tax)" OR
"59USD-300kg-25mb_4G" OR
"59USD-300kg" OR
"59USD"

大体上,连字符 (-) 会分解该字符串的一部分。

我想获取传递关键字或参数的字符串部分,例如:

String str = "59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee-1km(mm/hr)"; 

关键字或参数将是USD,然后结果将是

String expectString = "59USD";

String sourceStr = "59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee"; 

关键字或参数将是gb,然后结果将是

String expectString = "2gb+1gb_Toffee";

String sourceStr = "59USD-300kg-25mb_4G-48p/min(Incl. tax)"; 

关键字或参数将是min,然后结果将是

String expectString = "48p/min(Incl. tax)";

【问题讨论】:

    标签: java regex


    【解决方案1】:

    一个简单的解决方案是将字符串拆分为破折号(“-”),然后遍历拆分部分并匹配您的关键字。 但是,当有多个匹配项或根本没有匹配项时,您必须决定该怎么做。 以下代码包含 2 个基本实现,一个在列表中收集匹配项,另一个在第一次匹配后停止。 第一个将在没有匹配项时返回一个空列表,第二个将返回 null。

    import java.util.ArrayList;
    import java.util.List;
    
    public class KeywordMatcher {
    
        private static List<String> getKeywordMatches(String s, String keyword) {
            List<String> ret = new ArrayList<>();
            String[] parts = s.split("-");
            for (String part : parts) {
                if(part.contains(keyword))
                    ret.add(part);
            }
            
            return ret;
        }
    
        private static String getFirstKeywordMatch(String s, String keyword) {
            String[] parts = s.split("-");
            for (String part : parts) {
                if(part.contains(keyword))
                    return part;
            }
            
            return null;
        }
    
        public static void main(String[] args) {
            String s ="59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee-65USD-1km(mm/hr)";
            
            System.out.println(getKeywordMatches(s, "USD")); // prints [59USD, 65USD]
            System.out.println(getKeywordMatches(s, "min")); // prints [48p/min(Incl. tax)]
    
            System.out.println(getFirstKeywordMatch(s, "USD")); // prints 59USD
            System.out.println(getFirstKeywordMatch(s, "min")); // prints 48p/min(Incl. tax)
    
        }
    }
    

    更复杂的方法是在字符串中搜索下一个分隔符(“-”)和下一个关键字。迭代字符串直到它结束并跟踪分隔符和关键字的相对位置可以让您以更节省内存的方式获得相同的结果(因为与“拆分”方法不同,您不会在内存中创建任何新对象)。 然而,实现可能相当繁琐且难以阅读,因此我建议使用上述的一种,除非您有特定的性能要求或要搜索的字符串是 MB 大小的。

    编辑: 正如我在下面评论的那样,使用正则表达式看到了另一个答案,不幸的是效率极低。 看下面的sn-p来证明:

        private static String getFirstKeywordMatch(String s, String keyword) {
            String[] parts = s.split("-");
            for (String part : parts) {
                if(part.contains(keyword))
                    return part;
            }
            
            return null;
        }
    
        private static String lookForKeyword(String message, String keyword) {
            //System.out.println("Looking for keyword \"" + keyword + "\" in string \"" + message + "\"");
            String pattern = "^.*?-?([^-]*" + keyword +"[^-]*)-?.*$";
            Matcher matcher = Pattern.compile(pattern).matcher(message);
            if (matcher.matches()) {
                return matcher.group(1);
            }
            
            return null;
        }
    
        public static void main(String[] args) {
            String s ="59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee-65USD-1km(mm/hr)";
            
            long start=System.currentTimeMillis();
            for(int i=0; i<10000000; i++) {
                lookForKeyword(s, "USD");
            }
            System.out.println("Elapsed ms: " + (System.currentTimeMillis()-start));
            
            start=System.currentTimeMillis();
            for(int i=0; i<10000000; i++) {
                getFirstKeywordMatch(s, "USD");
            }
            System.out.println("Elapsed ms: " + (System.currentTimeMillis()-start));
        }
    

    在我的机器上,正则表达式方法比我的方法花费大约 4 倍。 因此,虽然我通常是正则表达式大使,但不幸的是,这不是他们最好的用例之一。

    【讨论】:

    • 关于 nquincampoix 的以下回答,使用正则表达式,不幸的是,从性能的角度来看,该解决方案的效率极低,比我的解决方案慢 4 倍左右(它本身并没有那么优化)。
    【解决方案2】:

    如果您对正则表达式感到满意,您可以这样做:

        void lookForKeyword(String message, String keyword) {
            System.out.println("Looking for keyword \"" + keyword + "\" in string \"" + message + "\"");
            String pattern = "^.*?-?([^-]*" + keyword +"[^-]*)-?.*$";
            Matcher matcher = Pattern.compile(pattern).matcher(message);
            if (matcher.matches()) {
                System.out.println("Found : \"" + matcher.group(1) + "\"");
            }
        }
    
        void test() {
            lookForKeyword("59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee-1km(mm/hr)", "USD");
            lookForKeyword("59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee", "gb");
            lookForKeyword("59USD-300kg-25mb_4G-48p/min(Incl. tax)", "min");
        }
    

    输出:

    Looking for keyword "USD" in string "59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee-1km(mm/hr)"
    Found : "59USD"
    Looking for keyword "gb" in string "59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee"
    Found : "2gb+1gb_Toffee"
    Looking for keyword "min" in string "59USD-300kg-25mb_4G-48p/min(Incl. tax)"
    Found : "48p/min(Incl. tax)"
    

    【讨论】:

      【解决方案3】:

      如果输入字符串的结构是一致的,则可以借助正则表达式the named groups进行描述,然后可以应用组的名称从匹配的字符串中获取适当的“字段”。

      组的模式如下: (?&lt;USD&gt;[^-]+):尖括号中的组名,[^-]+ -- 1 个或多个非破折号

      第一个组后面是 N 个嵌套的可选命名组。

      String[] strs = {
          "59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee-1km(mm/hr)",
          "59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee",
          "59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y",
          "59USD-300kg-25mb_4G-48p/min(Incl. tax)",
          "59USD-300kg-25mb_4G",
          "59USD-300kg",
          "59USD"
      };
      Pattern data = Pattern.compile("(?<USD>[^-]+)(-(?<kg>[^-]+)(-(?<mb>[^-]+)(-(?<min>[^-]+)(-(?<y>[^-]+)(-(?<gb>[^-]+)(-(?<km>[^-]+))?)?)?)?)?)?");
      for (String str : strs) {
          Matcher m = data.matcher(str);
          if (m.matches()) {
              System.out.println(str);
              System.out.println("\tUSD:\t" + m.group("USD"));
              System.out.println("\tkg :\t" + m.group("kg"));
              System.out.println("\tmb :\t" + m.group("mb"));
              System.out.println("\tmin:\t" + m.group("min"));
              System.out.println("\ty  :\t" + m.group("y"));
              System.out.println("\tgb :\t" + m.group("gb"));
              System.out.println("\tkm :\t" + m.group("km"));
              System.out.println("----");
          }
      }
      

      输出:

      59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee-1km(mm/hr)
          USD:    59USD
          kg :    300kg
          mb :    25mb_4G
          min:    48p/min(Incl. tax)
          y  :    70y
          gb :    2gb+1gb_Toffee
          km :    1km(mm/hr)
      ----
      59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y-2gb+1gb_Toffee
          USD:    59USD
          kg :    300kg
          mb :    25mb_4G
          min:    48p/min(Incl. tax)
          y  :    70y
          gb :    2gb+1gb_Toffee
          km :    null
      ----
      59USD-300kg-25mb_4G-48p/min(Incl. tax)-70y
          USD:    59USD
          kg :    300kg
          mb :    25mb_4G
          min:    48p/min(Incl. tax)
          y  :    70y
          gb :    null
          km :    null
      ----
      59USD-300kg-25mb_4G-48p/min(Incl. tax)
          USD:    59USD
          kg :    300kg
          mb :    25mb_4G
          min:    48p/min(Incl. tax)
          y  :    null
          gb :    null
          km :    null
      ----
      59USD-300kg-25mb_4G
          USD:    59USD
          kg :    300kg
          mb :    25mb_4G
          min:    null
          y  :    null
          gb :    null
          km :    null
      ----
      59USD-300kg
          USD:    59USD
          kg :    300kg
          mb :    null
          min:    null
          y  :    null
          gb :    null
          km :    null
      ----
      59USD
          USD:    59USD
          kg :    null
          mb :    null
          min:    null
          y  :    null
          gb :    null
          km :    null
      ----
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-26
        • 1970-01-01
        • 2013-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多