【问题标题】:Replace a specific (not all the matches) regex match on java or kotlin替换 java 或 kotlin 上的特定(不是所有匹配项)正则表达式匹配项
【发布时间】:2020-05-10 13:15:39
【问题描述】:

例如,我在正则表达式替换系统中有不同的正则表达式

"([e][u][r])+" = "euros"
"([e][u][r][o][s])+" = "currency"

但我想替换:

 1. The longest match for all the regex occurrences if more than 2 regex are true for the same part of text
 2. Just apply one time a rule for a part of text

如果我有类似这样的文字(文字不被行分割)

150,00 euros
42,00 eur
12,00 eureureuros

我有这种情况:

第一行出现两次

eur = euros (first line, match 3 characters)
euros = currency (first line, match 5 characters)

我们选择最长的(欧元=货币)

第二行,出现一次

eur = euros (second line, match 3 characters)

第三行,出现两次

eur = euros (match 9 characters)
euros = currency (match 5 characters)

结果必须是

150,00 currency (because euros = currency is the longest match)
42,00 euros (because we apply eur = euros but after that we DON'T apply euros = currency because we just apply one replacement for a part of text)
12,00 eurosos

有没有办法复制这种行为?

提前致谢!!

【问题讨论】:

  • “12,00 eureureuros”的结果究竟应该是什么。是“12,00 欧元”吗?那么“12,00 euroseuroseur”呢?
  • 嗨,保罗,这是因为我们需要替换最大的规则,以防两个或多个规则与文本的某些部分重合 eur 规则比“欧元”规则匹配的时间更长。结果将是欧元

标签: java android regex kotlin


【解决方案1】:

这回答了最初的问题。
您可以使用函数replace() 两次。
替换顺序很重要。
首先用"currency"替换最长的"euros",然后用"euros"替换"eur"
在您的情况下,只有 1 个替代品真正起作用。
对于"150,00 euros"

val s1 = "150,00 euros"
val new1 = s1.replace("euros", "currency").replace("eur", "euros")
println(new1)

结果:

150,00 currency

对于"42,00 eur"

val s2 = "42,00 eur"
val new2 = s2.replace("euros", "currency").replace("eur", "euros")
println(new2)

结果:

42,00 euros

【讨论】:

  • 我们不能分开行,我们必须将所有的文本作为一个单元来处理。然后,就更难了,因为我们必须根据匹配大小应用一个或其他规则......谢谢!!!
  • 在我的回答中,我有 2 个示例,每个案例 1 个。我不分开行。如果s 包含您的字符串,那么s.replace("euros", "currency").replace("eur", "euros") 在任何情况下都可以使用。
  • 例如,在这样的方向:12,00 eureureuros,使用替换系统我们将获得 12,00 eureureur[currency],因为我们获得欧元 = 货币,但我们有一个最长的匹配使用 eur = euros 规则 -> [eureureureur]os
  • 您的问题没有提及您在评论中发布的任何这些案例。
  • 所以你所做的是使这个答案无效并且答案已经被否决了。
【解决方案2】:

我会这样解决它:jdoodle.com/a/23Xw

public class MyClass {
   static List<Replacement> _regexes = new ArrayList<Replacement>();

   private static String parseWord(String word) {
        // Variables for holding the best match.
        String longest = "";
        String replacement = "";

        // Check all possible replacements.
        for (Replacement regex: _regexes) {
            // Find the longest possible match.
            Pattern p = Pattern.compile("(" + regex.Source + ")+");
            Matcher m = p.matcher(word);

            // Check all matches and store it if one is longer that the current one.
            while(m.find()) {
                String match = m.group();
                if (match.length() > longest.length()) {
                    longest = match;
                    replacement = regex.Target;
                }
            }
        }

        // Finally apply the replacement.
        String result = word.replace(longest, replacement);

        return result;
    }

    private static String parse(String text) {
        // Split text into words.
        List<String> words = Arrays.asList(text.split(" "));
        // Apply replacements.
        words = words.stream().map(word -> parseWord(word)).collect(Collectors.toList());
        // Join the words again to a text.
        return String.join(" ", words);
    }


    public static void main(String args[]) {
      _regexes.add(new Replacement("euros", "currency"));
      _regexes.add(new Replacement("eur", "euros"));
      Collections.sort(_regexes);

      List<String> data = Arrays.asList("150,00 euros", "42,00 eur", "12,00 eureureuros", "15,00 euroseuroseuroseur euros eur");
      for (String text: data) {
          String result = parse(text);
          System.out.println(text + " - " + result);
      }
    }
}

public class Replacement implements Comparable<Replacement> {
  public String Source;
  public String Target;

  public Replacement(String source, String target) {
      this.Source = source;
      this.Target = target;
  }

  @Override
  public int compareTo(Replacement r) {
    return r.Source.length();
  }  
}

【讨论】:

  • 这个实现还是挺不错的,但是还是不能正常工作,如果文本没有按行分割,比如List data = Arrays.asList("150,00 euros 42, 00 欧元 12,00 欧元 15,00 欧元");
  • 在这种情况下会发生什么?你在谈论“只有最长的匹配应该被替换”,这将是“euroseuroseuroseur”。这正是代码所做的。如果你想要不同,你需要考虑如何将你的文本分成适当的部分。
  • 那么,你认为如果我不将文本分成几行,就没有可能实现吗?也许你是对的,我必须这样想......问题是“只有最长的匹配应该被替换,以防文本的同一部分出现歧义,但是如果我们为文本的两个单独部分匹配两个单独的正则表达式,我们必须同时替换两者,例如“12,00 euros eur”将导致“12,00 currency euros”
  • 只要规则定义正确,几乎所有东西都有一个实现。 ;) 我更改了实现,现在替换是按单词完成的。
猜你喜欢
  • 2016-11-04
  • 1970-01-01
  • 1970-01-01
  • 2016-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-29
相关资源
最近更新 更多