【问题标题】:how can I capture part of a string using regular expressions?如何使用正则表达式捕获字符串的一部分?
【发布时间】:2017-07-01 05:23:52
【问题描述】:

(在java中)我想创建一个函数来使用正则表达式提取字符串的一部分:

public HashMap<Integer,String> extract(String sentence, String expression){
} 

//我需要这样发送一个句子例如:

HashMap<Integer,String> parts =extract("hello Jhon how are you", "(hello|hi) @1 how are @2");

// 表达式验证:句子必须以 hello 或 hi 开头,接下来是一个单词或一组单词,接下来是单词:“how are”,接下来是额外的其他单词 // 我想得到这个:

parts.get(1) --> "Jhon"
parts.get(2) --> "you"

//但是如果我给这个函数返回null:

extract("any other words","hello @1 how are @2");

我在没有正则表达式的情况下执行此操作,但代码变得有点大,我不确定使用正则表达式是否会更好以获得更快的过程,以及如何使用正则表达式来完成。

【问题讨论】:

  • 如果您的要求是您可以使用@n 传递一个字符串来获取参数,您可以编写代码将每个@n 替换为一个捕获组。如果expression 中可能有其他捕获组,这将导致编号失效,但您可以使用命名的捕获组,它应该不受该问题的影响。见docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
  • 如果我不清楚...您可以编写代码将每个 @n 替换为捕获组,并将生成的字符串用作正则表达式。

标签: java regex


【解决方案1】:

感谢@ajb 的评论。我已经修改了我的问题以满足奥马尔的要求。 比我想象的要复杂,哈哈。

我假设 Omar 想使用他提供的正则表达式来捕获特定的单词。他使用@1,@2 ... @n 来表示他要捕获的内容,整数值也是从地图中检索目标的关键。

编辑,OP想把@n放到括号里,我会预处理表达式,用“(?:”替换“(”。如果是这样的话,组仍然会生效但不能捕获。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
    public static void main(String args[]){

        Test test = new Test();
        String sentence1 = "whats the number of apple";
        String expression1 = "whats the (number of @1|@1s number)";
        HashMap<Integer, String> map1 = test.extract(sentence1, expression1);
        System.out.println(map1);
        String sentence2 = "whats the bananas number";
        HashMap<Integer, String> map2 = test.extract(sentence2, expression1);
        System.out.println(map2);
        String sentence3 = "hello Jhon how are you";
        String expression3 = "(hello|hi) @1 how are @2";
        HashMap<Integer, String> map3 = test.extract(sentence3, expression3);
        System.out.println(map3);
    }

    public HashMap<Integer,String> extract(String sentence, String expression){
        expression = expression.replaceAll("\\(", "\\(?:");
        ArrayList<Integer> keys = new ArrayList<Integer>();
        String regex4Expression = "@([\\d]*)";
        Pattern pattern4Expression = Pattern.compile(regex4Expression);
        Matcher matcher4Expression = pattern4Expression.matcher(expression);
        while(matcher4Expression.find()){
            for(int i = 1; i <= matcher4Expression.groupCount(); i++){
                if(!keys.contains(Integer.valueOf(matcher4Expression.group(i)))){
                    keys.add(Integer.valueOf(matcher4Expression.group(i)));
                }
            }
        }
        String regex = expression.replaceAll("@[\\d]*", "([\\\\w]*)");
        HashMap<Integer, String> map = new HashMap<Integer, String>();
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(sentence);

        while(matcher.find()){
            ArrayList<String> targets = new ArrayList<String>();
            for(int i = 1; i <= matcher.groupCount(); i++){
                if(matcher.group(i) != null){
                    targets.add(matcher.group(i));
                }
            }
            for(int j = 0; j < keys.size(); j++){
                map.put(j + 1, targets.get(j));
            }
        }
        return map;
    } 
}

结果如下

{1=apple}
{1=banana}
{1=Jhon, 2=you}

【讨论】:

  • 问题开始于“我想创建一个函数”。你没有向他展示任何可以帮助他创建他想要的功能的东西。你只向他展示了如何处理一个特殊情况。
  • @ajb 谢谢你的提醒。我首先误解了这个问题。
  • 非常感谢,我正在修改代码。我想知道我必须做些什么才能让括号中的任何'@'?引入这样的表达式:“whats the (number of @1|@1s number)”
  • @OmarVillanueva 我仍将使用正则表达式来满足即将到来的需求。查看编辑。
猜你喜欢
  • 2023-03-31
  • 2019-10-12
  • 1970-01-01
  • 2021-12-10
  • 2021-09-27
  • 2019-10-09
  • 2017-03-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多