替换字符串

时间:2016-08-02 14:33:03

标签: java string replace

我正在尝试将相同的替换指令应用于不同的输入字符串数千次,并且开销尽可能小。我需要考虑两件事:

  1. 搜索字符串的长度不一定相同:一个可能只是“a”,另一个可能是“ch”,而另一个可能是“sch”
  2. 已经更换的内容不得再次更换:如果替换模式是[a-> e; e-> a],“beat”应该变成“baet”,而不是“baat”或“beet”。
  3. 考虑到这一点,这是我提出的代码:

    public class Replacements {
        private String[] search;
        private String[] replace;
        Replacements(String[] s, String[] r)
        {
            if (s.length!=r.length) throw new IllegalArgumentException();
            Map<String,String> map = new HashMap<String,String>();
            for (int i=0;i<s.length;i++)
            {
                map.put(s[i], r[i]);
            }
            List<String> sortedKeys = new ArrayList(map.keySet());
            Collections.sort(sortedKeys, new StringLengthComparator());
            this.search = sortedKeys.toArray(new String[0]);
            Stack<String> r2 = new Stack<>();
            sortedKeys.stream().forEach((i) -> {
                r2.push(map.get(i));
            });
            this.replace = r2.toArray(new String[0]);
        }
        public String replace(String input)
        {
            return replace(input,0);
        }
        private String replace(String input,int i)
        {
            String out = "";
            List<String> parts = Arrays.asList(input.split(this.search[i],-1));
            for (Iterator it = parts.iterator(); it.hasNext();)
            {
                String part = it.next().toString();
                if (part.length()>0 && i<this.search.length-1) out += replace(part,i+1);
                if (it.hasNext()) out += this.replace[i];
            }
            return out;
        }
    }
    

    然后

    String[] words;
    //fill variable words
    String[] s_input = "ou|u|c|ch|ce|ci".split("\\|",-1);
    String[] r_input = "u|a|k|c|se|si".split("\\|",-1);
    Replacements reps = new Replacements(s_input,r_input);
    for (String word : words) {
        System.out.println(reps.replace(word));
    }
    

    s_inputr_input取决于用户,因此它们只是示例,就像程序实际上不会使用println()一样)

    此代码可确保首先查找较长的搜索字符串,并涵盖上述第二个条件。

    然而,这是非常昂贵的。什么是最有效的方法来完成我在这里做的事情(特别是如果words中的字符串数量非常大)?

    使用我当前的代码,“沙发”应该转换为“kuc”(除非它没有,显然;它现在确实如此,感谢split(p,-1)中的-1)

3 个答案:

答案 0 :(得分:1)

这不是一个完整的解决方案,但它展示了如何扫描输入并在一次通过中查找所有目标子串。您可以使用public static void main(String[] args) throws Exception { Pattern p = Pattern.compile("(ou|ch|ce|ci|u|c)"); Matcher m = p.matcher("auouuchcceaecxici"); while (m.find()) { MatchResult r = m.toMatchResult(); System.out.printf("s=%d e=%d '%s'\n", r.start(), r.end(), r.group()); } } 来汇总结果,查找当前正在执行的地图中的替换。使用开始和结束索引来处理不匹配段的复制。

s=1 e=2 'u'
s=2 e=4 'ou'
s=4 e=5 'u'
s=5 e=7 'ch'
s=7 e=8 'c'
s=8 e=10 'ce'
s=12 e=13 'c'
s=15 e=17 'ci'

输出:

{{1}}

请注意,正则表达式中的字符串必须按照下降长度的顺序排序才能正常工作。

答案 1 :(得分:0)

可以从密钥生成正则表达式模式并将其留给该模块进行优化。

显然

"(ou|u|ch|ce|ci|c)"

需要通过反向排序或立即作为树来处理ce / ci / c:

"(c(e|h|i)?|ou|u)"

然后

String soughtKeys = "ou|u|ch|ce|ci|c"; // c last
String replacements = "u|a|c|se|si|k";
Map<String, String> map = new HashMap<>();
... fill map

Pattern pattern = Pattern.compile("(" + soughtKeys + ")");

for (String word : words) {
    StringBuffer sb = new StringBuffer();
    Matcher m = pattern.matcher(word);
    while (m.find()) {
        m.appendReplacement(sb, map.get(m.group());
    }
    m.appendTail(sb);
    System.out.printf("%s -> %s%n", word, sb.toString());
}

优势在于正则表达式非常智能(虽然速度很慢),并且替换不会替换为替换文本。

答案 2 :(得分:0)

{{1}}