我从 mysql 字段中获取了一个长字符串,其中包含 mediawiki 页面的数据。我必须替换该 mediawiki 页面中的字符串,但当字符串在 mediawiki 链接中时则不必替换。mediawiki 链接由双方括号标识。
例如,替换“这是必须替换的术语”中的“术语”,但不要替换“这是不能替换的术语”
解决方案可以是mysql或sed,awk或其他任何程序。请帮忙。谢谢。
答案1
我更喜欢使用可以使用多字符分隔符分割字符串的工具来解决此类问题。您可以使用“排除模式”作为分隔符,然后对非分隔符的元素进行替换。因为我喜欢 perl,所以我会在这里做一个 perl 单行代码。:)
首先,因为“perl”不是你建议的解决方案之一,所以我猜你不擅长 perl。因此,我将从你需要了解的一些有关 perl 的知识开始,以了解其工作原理:
如果在 perl 函数中用括号括住拆分模式split
,分隔符将作为 所返回数组中的附加元素保留split
。使用可获得和\[\[.*?\]\]
之间包含的最小字符串,因此在返回的数组中,我们可以选择不以 开头的元素并仅对这些元素进行替换。使用 foreach 和 map,$_ 将是数组元素的引用(指针),因此对 $_ 的更改会更改数组元素。因此,在更改数组之后,我们可以将可能被修改的元素和分隔符(仍然按正确顺序)用空字符重新连接在一起。此外,我喜欢使用而其他人更喜欢(我更喜欢使用而不是,因为看起来有点像并且看起来像;))。这不是代码高尔夫,我认为我的方式更具可读性。:)[[
]]
[[
unless()
if(!)
q{}
''
''
"
""
''''
哦,以防万一这也是新的:perl -lne
--l
透明地处理换行符,我想我们在这里真的不关心,但这是习惯。将-n
代码放在while(<>){}
.
综上所述,这里有一个可行的(但毫无意义的)例子,将所有非链接“a”替换为“pie”:
danny@host [/home/danny]
$ cat testfile
a b c d [[a]] b c d [[ moo a moo]] a
I like to eat [[meat]] on a plate
danny@host [/home/danny]
$ perl -nle'@l=split(/(\[\[.*?\]\])/); foreach (@l){s/a/pie/g unless(/^\[\[/)};
print join(q{}, @l)' testfile
pie b c d [[a]] b c d [[ moo a moo]] pie
I like to epiet [[meat]] on pie plpiete
答案2
只需使用pywibot 的 replace.py。
replace.py -exceptinside:link -regex "Term" "New term"
其他答案都是错误的(不可靠的),并且不必要地复杂。
答案3
以下是一些应该适合您的代码。在 AIX 上的 bash 上进行了测试:
#!/usr/bin/bash
#filename: test2.sh
searchandreplace() {
thisline=$1
echo $thisline | awk '
BEGIN { FS= "[" }
/\[/ {sub(/Term/,"foobar");print}
!/\[/ {print}
'
}
infile=test.in
cat $infile | while read line
do
searchandreplace "$line"
done
这是 test.in:
"Here is the Term that has to be replaced" "Here [[is the Term that]] must not be replaced"
third line
运行时示例: