【问题标题】:Java regex to capture all words in stringsJava 正则表达式捕获字符串中的所有单词
【发布时间】:2022-10-15 14:34:55
【问题描述】:

我正在寻找一个能够捕获字符串中所有单词的正则表达式。

我有以下输入字符串

  1. 约翰·史密斯先生
  2. 约翰先生
  3. J小姐

    预期产出

    1. {“约翰”、“史密斯”、“先生”}
    2. {“约翰”,“先生”}
    3. {“J”,“小姐”}

      我已经编写了下面的正则表达式,它工作得很好,但它不适用于输入字符串 2 和 3。输入字符串应该只有字母字符(没有数字或特殊字符)。

      ((?:[a-z]*[a-z]+)).*?((?:[a-z][a-z]+)).*?((?:[a-z][a-z]+))

      如果输入字符串包含像JOHN 12345 这样的数字,那么正则表达式不应捕获任何内容。

      你能帮我改进我的正则表达式来捕捉预期的结果吗?

【问题讨论】:

  • 你可以匹配[a-zA-Z ]*,如果它是真的,你在空格上分割
  • 每个字符串最多三个单词吗?
  • 有时是2个字,有时是3个。字数不一致。
  • 这可能会简化为更像Pattern p = Pattern.compile("([a-z]+).*?([a-z]{2,}).*?([a-z]+)?"); 的东西(如果你真的想要它们,你可以恢复非捕获但不要冗余双括号)。您正在尝试匹配只有三件事

标签: java regex


【解决方案1】:

我可以建议替代方案吗? 将字符串 split() 方法与正则表达式一起使用。见下文

        String[] arr = {"JOHN SMITH MR",
                "JOHN MR",
                "J MISS",
        "JOHN 1234"};

        for (String s : arr) {
            Matcher m = Pattern.compile("[0-9]+").matcher(s);
            if(m.find()){
                continue;
            }
            String[] arr2 = s.split(" ");
            log.info("arr2 = {}", Arrays.asList(arr2));
        }

你有你的输出

【讨论】:

    【解决方案2】:

    有一个现有代码从输入 rawNameString 中提取名字和标题。如果输入字符串仅包含名字和标题(“JOHN MR”),则代码可以正常工作,但如果输入字符串包含名字、中间名和标题(“JOHN SMITH MR”),则代码将无法正常工作。在这种情况下,标题被映射为不正确的值。 目标是仅提取名字和头衔。

    现有代码:

    Pattern  NAME_PATTERN = Pattern.compile("((?:[a-z]*[a-z]+))" + ".*?" + "((?:[a-z][a-z]+))", Pattern.CASE_INSENSITIVE);
            String rawNameString = "JOHN MR";
    
            Name name = new Name();
            Matcher nameMatcher = NAME_PATTERN.matcher(rawNameString);
            if (nameMatcher.find()) {
                //tile
                name.setTitle(nameMatcher.group(2));
                //firstname
                name.setFirstName(nameMatcher.group(1));
            } else {
                throw new Exception("Invalid Name");
            }
    

    我修改了代码以捕获名字和标题,而与输入字符串中的单词数无关。

    Pattern  NAME_PATTERN = Pattern.compile("^[a-zA-Z ]*$");
            String rawNameString = "JOHN SMITH MR";
    
            Name name = new Name();
            Matcher matcher = NAME_PATTERN.matcher(rawNameString);
            if(matcher.find()) {
                List<String> nameList = Arrays.asList(rawNameString.split("\s+"));
                if(nameList.isEmpty())
                    throw new Exception("Invalid Name ");
                name.setFirstName(nameList.get(0));
                name.setTitle(nameList.get(nameList.size()-1));
            } else {
                throw new Exception("Invalid Name ");
            }
    

    我希望更改正则表达式而不是更改 Java 代码。

    【讨论】:

    • 目标是仅提取名字和头衔。那么所有这些正则表达式的东西都是矫枉过正的。 String.split("\s+"); 将在两个标记中的第二个与标题匹配的情况下为您完成
    • @g00se,是的,这是正确的,但如果输入字符串包含数值,那么它不应该捕获任何东西。如果我们只使用 split 那么 numeric 也会被捕获。
    【解决方案3】:

    你可以使用这个:

    ^([a-zA-Z]+) *([a-zA-Z]+)* *([a-zA-Z]+)* *$
    

    【讨论】:

      【解决方案4】:

      选择:

      使用的正则表达式:

      "[^a-zA-Z\s]"
      

      正则表达式匹配非字母或非空格。

      请参阅上下文和测试台中的正则表达式,如下:

      public static void main(String[] args) {
          String input1 = "JOHN SMITH MR";
          String input2 = "JOHN MR";
          String input3 = "J MISS";
          String input4 = "JOHN  12345";
      
          List<String> inputList = Arrays.asList(input1, input2, input3, input4);
      
          Pattern findAnyNonLetterNonSpacePattern = Pattern.compile("[^a-zA-Z\s]");
          for (String input : inputList) {
              if (findAnyNonLetterNonSpacePattern.matcher(input).find()) continue;
              List<String> stringList = Arrays.asList(input.split("\s+"));
              System.out.println(stringList);
          }
      }
      

      输出:

      [JOHN, SMITH, MR]
      [JOHN, MR]
      [J, MISS]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-23
        • 1970-01-01
        • 2012-08-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多