我试图用尽可能少的开销将相同的替换指令几千次应用于不同的输入字符串。我需要考虑两两件事是:替换字符串中的多个子字符串的有效且无干扰的方法
- 搜索字符串不一定都是相同的长度:一个可能只是“一”,另一种可能是“CH”,另一种可能是“SCH”
- 已经替换的内容不应再次替换:如果替换模式为[a-> e; e-> a],“beat”应该变成“baet”,而不是“baat”或“甜菜”。
考虑到这一点,这是我想出了代码:
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_input
和r_input
将高达用户,因此他们只是举例,就像程序实际上不会使用println()
)
This代码确保首先查找更长的搜索字符串,并且还涵盖上面的第二个条件。
然而,它是相当昂贵的。什么是最有效的方式来完成我在这里做的事情(特别是如果words
中的字符串数量非常大)?
随着我当前的代码,“沙发”应该被转换为“KUC”(除了没有,显然,它现在,多亏了-1 split(p,-1)
)
你会遇到'split(“|”)'(参数是一个正则表达式)的麻烦。如果你真的必须使用'split(“\\ |”));但是最好是明确地构造你的地图,并将它作为参数传递给'Replacements'。 –
'split(“|”)'部分只是为了说明's_input'和'r_input'内部的内容。实际的代码会以不同的方式派生出这些内容。但我会在这里编辑代码以消除这种情况。 – joelproko
说实话,如果你想要尽可能少的开销,理想的解决方案是迭代char数组(一次)并跟踪历史记录,以替换任何代替多个char的任何东西。也就是抛弃任何正则表达式。 – Rogue