简体   繁体   English

从字符串中提取变量值

[英]Extract variable values from String

Given that the user can enter values in specific formats only, I need to extract relevant sections of that string into Java variables.鉴于用户只能以特定格式输入值,我需要将该字符串的相关部分提取到 Java 变量中。

Say for instance acceptable formats are:-比如说可接受的格式是:-

String types[] = {"The quick brown ${animal} jumped over the lazy ${target}.",
                  "${target} loves ${animal}.",
                  "${animal} became friends with ${target}"};

Variables:-变量:-

private String animal;
private String target;

Now if the user enters "The quick brown fox jumped over the lazy dog."现在,如果用户输入"The quick brown fox jumped over the lazy dog." , the animal variable should be set to "fox" and target variable should be set to "dog" . , 动物变量应设置为"fox" ,目标变量应设置为"dog"

If the user input matches none of the given types, it should display an error.如果用户输入与给定类型都不匹配,则应显示错误。

Basically I am trying to do the inverse of what org.apache.commons.lang.text.StrSubstitutor does.基本上我试图做与org.apache.commons.lang.text.StrSubstitutor做的相反的事情。

My approach (looks inefficient, hence asking for help):-我的方法(看起来效率低下,因此寻求帮助):-

Create regex patterns to find out the type of the entered string and then write different logic for each of the type.创建正则表达式模式以找出输入字符串的类型,然后为每种类型编写不同的逻辑。 For example, for the first type, get the word after the word "brown" and assign it to variable animal and so on.例如,对于第一种类型,获取单词“brown”之后的单词并将其分配给变量animal等。

Using @Josh Withee's answer :- 使用@Josh Withee的答案 :-

/**
 * @param input         String from which values need to be extracted
 * @param templates     Valid regex patterns with capturing groups
 * @param variableNames Names for named capturing groups
 * @return Map with variableNames as the keys and the extracted strings as map values
 * OR an empty, non-null map if the input doesn't match with any template, or if there is no group with the given variableNames
 */
public static Map<String, String> extractVariablesFromString(String input, List<String> templates, String... variableNames) {
        Map<String, String> resultMap = new HashMap<>();
        Optional<String> matchedTemplate = templates.stream().filter(input::matches).findFirst();
        matchedTemplate.ifPresent(t -> {
            Matcher m = Pattern.compile(t).matcher(input);
            m.find();
            Arrays.stream(variableNames)
                    .forEach(v -> {
                        try {
                            resultMap.put(v, m.group(v));
                        } catch (IllegalArgumentException e) {
                        }
                    });
        });
        return resultMap;
    }

Tests:- 测试: -

    @Test
    public void shouldExtractVariablesFromString() {
        String input = "The quick brown fox jumped over the lazy dog.";
        String types[] = {"The quick brown (?<animal>.*) jumped over the lazy (?<target>.*).",
                "(?<target>.*) loves (?<animal>.*).",
                "(?<animal>.*) became friends with (?<target>.*)"};
        Map<String, String> resultMap = StringUtils.extractVariablesFromString(input, Arrays.asList(types), "animal", "target1", "target");
        Assert.assertEquals("fox", resultMap.get("animal"));
        Assert.assertEquals("dog", resultMap.get("target"));
        Assert.assertFalse(resultMap.containsKey("target1"));
    }

    @Test
    public void shouldReturnEmptyMapIfInputDoesntMatchAnyPatternForVariableExtraction() {
        String input = "The brown fox passed under the lazy dog.";
        String types[] = {"The quick brown (?<animal>.*) jumped over the lazy (?<target>.*).",
                "(?<animal>.*) became friends with (?<target>.*)"};
        Map<String, String> resultMap = StringUtils.extractVariablesFromString(input, Arrays.asList(types), "animal", "target1", "target");
        Assert.assertTrue(resultMap.isEmpty());
    }

You can do this with named capture groups: 您可以使用命名捕获组来执行此操作:

String userInput = "dog loves fox.";

String types[] = {"The quick brown (?<animal>.*?) jumped over the lazy (?<target>.*?).",
                  "(?<target>.*?) loves (?<animal>.*?).",
                  "(?<animal>.*?) became friends with (?<target>.*?)"};

Matcher m;

for(int i=0; i<types.length(); i++;){
    if(userInput.matches(types[i]){
        m = Pattern.compile(types[i]).matcher(userInput);
        break;
    }
}

m.find();

String animal = m.group("animal");
String target = m.group("target");
/**
 *
 * @param input /Volumes/data/tmp/send/20999999/sx/0000000110-0000000051-007-20211207-01.txt
 * @param template /{baseDir}/send/{yyyyMMdd}/{organization}/{sendOrganization}-{receiveOrganization}-{fileType}-{date}-{batch}.txt
 * @param prefix
 * @param suffix
 * @return
 */
public static Map<String, String> extractVariables(final String input, final String template, final String prefix, final String suffix) {
    final HashSet<String> variableNames = new HashSet<>();
    String variableNamesRegex = "(" + prefix + "([^" + prefix + suffix + "]+?)" + suffix + ")";
    Pattern variableNamesPattern = Pattern.compile(variableNamesRegex);
    Matcher variableNamesMatcher = variableNamesPattern.matcher(template);
    while (variableNamesMatcher.find()) {
        variableNames.add(variableNamesMatcher.group(2));
    }
    final String regexTemplate = template.replaceAll(prefix, "(?<").replaceAll(suffix, ">.*)");
    Map<String, String> resultMap = new HashMap<>();
    Matcher matcher = Pattern.compile(regexTemplate).matcher(input);
    matcher.find();
    variableNames.forEach(v -> resultMap.put(v, matcher.group(v)));
    return resultMap;
}

usage like用法像

extractVariables(input, template2, "\\{", "\\}")提取变量(输入,模板2,“\\{”,“\\}”)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM