java替代连续字符串。代替
我想替换字符串输入中的一些字符串:
string=string.replace("<h1>","<big><big><big><b>");
string=string.replace("</h1>","</b></big></big></big>");
string=string.replace("<h2>","<big><big>");
string=string.replace("</h2>","</big></big>");
string=string.replace("<h3>","<big>");
string=string.replace("</h3>","</big>");
string=string.replace("<h4>","<b>");
string=string.replace("</h4>","</b>");
string=string.replace("<h5>","<small><b>");
string=string.replace("</h5>","</b><small>");
string=string.replace("<h6>","<small>");
string=string.replace("</h6>","</small>");
正如您所看到的,这种方法不是最好的,因为每次我都要搜索要替换的部分等,而字符串是不可变的。。。此外,输入量很大,这意味着需要考虑一些性能问题
有没有更好的方法来降低代码的复杂性
# 1 楼答案
你可以用
StringBuilder
做类似的事情,但在那种情况下,你必须自己实现appendReplacement
等等至于表达式,您也可以尝试匹配任何html标记(尽管这可能会导致问题,因为正则表达式和任意html不太适合),当查找没有任何结果时,您只需将匹配替换为自身
# 2 楼答案
我会这样做
tagEquals是一个检查标记名的函数
# 3 楼答案
尽管与^{} 相比^{} 是一个巨大的改进,但它仍然远远不是最佳的
StringBuilder.replace()
的问题是,如果替换的长度与可替换部分不同(适用于我们的情况),则可能必须分配更大的内部char
数组,并且必须复制内容,然后会发生替换(这也涉及复制)想象一下:你有一个包含10000个字符的文本。如果要将位于位置
1
(第二个字符)的"XY"
子字符串替换为"ABC"
,则实现必须重新分配一个至少大于1的char
缓冲区,必须将旧内容复制到新数组,它必须将9.997个字符(从3
位置开始)向右复制1,以将"ABC"
放在"XY"
位置,最后将"ABC"
的字符复制到起始位置1
。每次更换都必须这样做!这太慢了更快的解决方案:动态生成输出
我们可以动态地构建输出:不包含可替换文本的部分可以简单地附加到输出中,如果我们找到一个可替换的片段,我们会附加替换,而不是它。理论上,只需在输入上循环一次即可生成输出。听起来很简单,实现起来也不难
实施:
我们将使用预加载了可替换替换字符串映射的
Map
:下面是替换代码:(代码后面有更多解释)
测试它:
输出:(包装以避免滚动条)
这个解决方案比使用正则表达式要快,因为这需要很多开销,比如编译
Pattern
,创建Matcher
等等,而且regexp也更通用。它还会在引擎盖下创建许多临时对象,这些对象在更换后会被扔掉。在这里,我只使用了一个StringBuilder
(加上它下面的char
数组),代码只在输入String
上迭代一次。此外,这个解决方案比使用StringBuilder.replace()
要快得多,如本答案顶部所述注释和解释
我在
replaceTags()
方法中初始化了StringBuilder
,如下所示:所以基本上我创建它的初始容量是原始
String
长度的150%。这是因为我们替换的文本比替换的文本长,所以如果替换发生,输出显然会比输入长。为StringBuilder
提供更大的初始容量将不会导致任何内部char[]
重新分配(当然,所需的初始容量取决于可替换替换对及其在输入中的频率/出现率,但这+50%是一个很好的上限估计)我还利用了一个事实,即所有可替换字符串都以
'<'
字符开头,因此找到下一个潜在的可替换位置变得非常迅速:它只是一个简单的循环和
char
内的String
比较,而且由于它总是从pos
开始搜索(而不是从输入的开始),所以总体而言,代码只在输入String
上迭代一次最后,为了判断一个可替换的} 方法来检查可替换的stings,这也很快,因为它只需比较循环中的
String
是否在潜在位置发生,我们使用^{char
值,并在第一个不匹配的字符处返回还有一个加号:
问题没有提到它,但我们的输入是一个HTML文档。HTML标记不区分大小写,这意味着输入可能包含
<H1>
,而不是<h1>
对于这个算法来说,这不是问题。
String
类中的regionMatches()
有一个重载supports case-insensitive comparison:所以如果我们想修改我们的alg算法为了找到和替换相同但使用不同字母大小写的输入标记,我们只需修改这一行:
使用此修改后的代码,可替换标记将不区分大小写:
# 4 楼答案
StringBuilder由字符数组支持。因此,与字符串实例不同,它是可变的。因此,您可以在
StringBuilder
上调用indexOf()
和replace()
# 5 楼答案
您提供的特定示例似乎是HTML或XHTML。尝试使用正则表达式编辑HTML或XML会遇到很多问题。对于您似乎感兴趣的编辑类型,您应该考虑使用XSLT。另一种可能性是使用流式XML解析器SAX,让后端动态编写编辑后的输出。如果文本实际上是HTML,那么最好使用一个宽容的HTML解析器,比如JSoup,来构建文档的解析表示(比如DOM),并在输出之前对其进行处理
# 6 楼答案
对于性能-使用
StringBuilder
。 为了方便起见,您可以使用Map
来存储值和替换。。。要替换StringBuilder中的所有事件,可以在此处进行检查: Replace all occurrences of a String using StringBuilder?