我有一个像下面这样的 css 文件:
#layout.one-column #menu-secondary{background: #3c3c3c; height: 20px; font-family: 'Trebuchet MS'; font-weight: bold; font-size: 15px; padding: 10px;}
#layout.one-column #menu-secondary a {color: #FFF; text-decoration: none;}
#layout.one-column #menu-secondary ul {}
#layout.one-column #menu-secondary ul li {display: block; height: 30px; float: left; margin: 0 20px 0 0;}
.ofr h2 {font-size: 17px; height: 35px; margin: 0 10px 10px 10px;}
.ofr h2 a {color: #2a2a2a; text-decoration: none;}
#layout.one-column #menu-secondary ul li.active {background: url(../img/selected.gif) no-repeat bottom center;}
#layout.one-column #menu-secondary ul li a {display: block; float: left; padding: 0 10px;}
#layout.one-column #menu-secondary ul li a:hover {text-decoration: underline;}
如您所见,每一行的开头都有制表符/一对空格,字符串以 .whatever/#whatever 开头。我编写了一个小脚本,该脚本在某一时刻运行:
find css/myCSS.css -name "*.css" -type f -exec sed -i "s/\<$pattern\>/$replacer/g" {} \;
其中 $pattern
可以是 #layout
而 $replacer
可以是 #LAYOUT
。我想做的是,如果字符串是
#LAYOUT
替换 #layout
- 等于(
$pattern 前后的空格/制表符
) - 等于(
$pattern 之前的空格/制表符
)后跟点
加上任何内容(#pattern.whatever
) - 等于(
$pattern 之前的空格/制表符
)后跟#
加上任何内容(#pattern#whatever
) - 喜欢
#whatever.pattern
或#whatever#pattern(#whatever 之前和#pattern 之后的空格/制表符
)。
我希望我现在做到了, Crystal 般清晰:)
这里有一些例子,每一行中的#pattern 或 .pattern 都应该被替换:
#pattern <- blank spaces/tabs before and after the string
#pattern.bar <- blank spaces/tabs before #pattern and after .bar
.pattern#bar <- blank spaces/tabs before .pattern and after #bar
#foo.pattern <- blank spaces/tabs before #foo and after .pattern
.foo#pattern <- blank spaces/tabs before .foo and after #pattern
.pattern <- blank spaces/tabs before and after the string
我一直在尝试使用 sed 来完成它,但我无法通过,并且认为对于每天使用 sed 工作的人来说我可能会“轻松”。再次感谢 :)
最佳答案
如果您想根据需要重新定义单词边界,则需要枚举它们。一种方法是,获取边界模式并将其附加到最后:
echo "well #menu not #menu-foo #menu" | sed -r 's/#menu([ \t\n\r.!?,]|$)/#MENU\1/g'
well #MENU not #menu-foo #MENU
|$
是抓取文件结尾/输入案例结尾。
我仍然不知道前导 # 的作用,但我想如果您需要\1MENU\2 作为第一个分隔符模式,您可以应用这个想法。
更新 28.07,23:45:
- 等于($pattern 前后的空白/制表符)
[ \t]pattern[ \t]
- 等于($pattern 之前的空白/制表符)后跟点加上任何内容(#pattern.whatever)
[ \t]pattern.[^ \t]
对“任何”的详尽描述会更好。额外的点,是 - 允许的 - 我们如何识别“无论什么”结束?空格? - 等于($pattern 之前的空白/制表符)后跟 # 加上任何内容(#pattern#whatever)
[ \t]pattern#[^ \t]
好的,和上面一样,只是散列而不是点。 - 喜欢#whatever.pattern 或#whatever#pattern(#whatever 之前和#pattern 之后的空白/制表符)。
[ \t]#[^ \t].pattern[ \t]
或者[ \t]#[^ \t]#pattern[ \t]
没有。 2和3几乎一样。如果我们指的是 A 或 B,我们可以简单地组成一个组 [#.]。在组内,我们不需要屏蔽点,因为作为 clown 的点在组中没有任何意义。
没有。因此 2 和 3 合并为
[ \t]pattern[#.][^ \t][ \t]
但是!你不会用“随便”做任何事情。不管它是什么,它都没有改变。所以我们添加 # 和 .只是分隔符列表(空白和制表符)并返回它们(或空白或制表符),无论它们是什么:
[ \t]pattern([#. \t])
一个简单的测试:
echo "well #menu not #menu-false #menu.dot #menu#hash" \
| sed -r 's/[ \t]#menu([#. \t])/ #MENU\1/g'
well #MENU not #menu-false #MENU.dot #MENU#hash
这将修改#Menu 前面的内容,无论是空白还是制表符,始终为空白。如果需要,我们也可以捕获它。
| sed -r 's/([ \t])#menu([#. \t])/\1#MENU\2/g'
但是最后一条规则是什么,第 4 条,“whatever”领先于“pattern”?我们可以结合点和散列:
[ \t]#[^ \t][.#]menu[ \t]
将这种情况组合到我们的正则表达式中将允许#foo#pattern#bar。这变得越来越复杂了。我们最好开始一个全新的命令:
s/([ \t]#[^ \t]+[.#])menu[ \t]/\1MENU /g'
可以附加';'在上一个之后:
| sed -r 's/[ \t]#menu([#. \t])/ #MENU\1/g;s/([ \t]#[^ \t]+[.#])menu[ \t]/\1MENU /g'
所以我想我解决了您的 4 条规则,但顶部的示例只解决了其中的两条。你的尝试再次包括\<
和 \>
这只会令人困惑。
这是我自制的例子,包括规则 4 的情况:
echo "well #bar.menu and #foo#menu #menu not #menu-false #menu.dot #menu#hash" \
| sed -r 's/[ \t]#menu([#. \t])/ #MENU\1/g;s/([ \t]#[^ \t]+[#.])menu[ \t]/\1MENU /g'
well #bar.MENU and #foo#MENU #MENU not #menu-false #MENU.dot #MENU#hash
关于regex - 使 sed 仅替换精确的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6832705/