显然,我正在尝试将一份巨大文档中每个段落的第一个单词斜体化。我认为添加前缀相对容易,但如何仅描绘后缀的第一个单词而不是行尾?该文件应该以空格分隔。
sed -e 's/^/<i>/' file > file.new
我是否需要使用不同的语法运行 sed 两次,还是可以使用一个命令来实现?我正在输出到一个新文件,以防万一搞砸了。
以下是该文件的几行示例:
Snapdragon Plant with a two-lipped flower.
Snap-fastener = *press-stud.
Snapper Any of several edible marine fish.
Snappish 1 curt; ill-tempered; sharp. 2 inclined to snap.
我希望它如下所示:
<i>Snapdragon</i> Plant with a two-lipped flower.
<i>Snap-fastener</i> = *press-stud.
<i>Snapper</i> Any of several edible marine fish.
<i>Snappish</i> 1 curt; ill-tempered; sharp. 2 inclined to snap.
并非所有的行都是单行的,有些术语有多行定义。
答案1
使用 sed,
- 如果该行的开头有一个字母,那么
- 捕获任意数量的非空白字符并且
- 将那些捕获的字符替换为周围的
<i>
...</i>
。
像这样:
sed '/^[a-zA-Z]/ s!\([^ ]*\)!<i>\1</i>!' < file > file.new
在此示例输入上:
Snapdragon Plant with a two-lipped flower.
Snap-fastener = *press-stud.
Snapper Any of several edible marine fish.
Snappish 1 curt; ill-tempered; sharp. 2 inclined to snap.
输出是:
<i>Snapdragon</i> Plant with a two-lipped flower.
<i>Snap-fastener</i> = *press-stud.
<i>Snapper</i> Any of several edible marine fish.
<i>Snappish</i> 1 curt; ill-tempered; sharp. 2 inclined to snap.
分解 sed 命令的各个部分:
/^[a-zA-Z]/
-- 这是一个地址过滤器;这意味着仅将后续命令应用于与此正则表达式匹配的行。正则表达式要求行首后面必须有一个字母(小写a-z
或大写) 。A-Z
^
s!\([^ ]*\)!<i>\1</i>!
-- 这是搜索和替换命令。它在搜索和替换之间使用分隔符;常见的分隔符是正斜杠,但由于替换文本有正斜杠,所以我将分隔符更改为感叹号!
。搜索词有两部分:捕获括号(必须转义)和正则表达式[^ ]*
,它表示:“匹配除空格之外的任何内容,零次或多次*
。替换文本引用回捕获的内容将其分组\1
并用 HTML 标签包围。
要另外用段落标签包裹每个非空行,请添加另一个 sed 表达式:
sed -e '/^[a-zA-Z]/ s!\([^ ]*\)!<i>\1</i>!' -e '/./ { s/^/<p>/; s!$!</p>! }' < file
附加表达式表示:
- 匹配具有一个(任何)字符的行——这会跳过空白行
{
将接下来的两个命令组合在一起- 搜索行首并将其替换
^
为开头段落标记 - 搜索行尾并将其替换
$
为结束段落标记 }
结束分组
答案2
您可以通过以下方式执行此操作sed
:
$ sed '/^$/n;s#^\([^ ]*\)#<i>\1</i>#' input.txt
<i>Snapdragon</i> Plant with a two-lipped flower.
<i>Snap-fastener</i> = *press-stud.
<i>Snapper</i> Any of several edible marine fish.
<i>Snappish</i> 1 curt; ill-tempered; sharp. 2 inclined to snap.
解释
以上sed
包括2块。第一个块检测任何空白行,/^$/
并跳过它们n
。
- 跳过任何空白行
/^$/n
第二个块完成所有繁重的工作s#..#..#
,并检测不包含空格的子字符串\([^ ]*\)
。该模式通过包装它的 来“保存” \(..\)
,因此我们可以稍后通过 来重用它\1
。
- 将子字符串匹配到第一个空格
\([^ ]*\)
- 保存匹配,
\1
并将其包装为<i>...</i>
答案3
您可以尝试使用 awk:
awk '{$1="<i>$1</i>"; print $0}' file > file.new
答案4
sed
扩展正则表达式
将<i>
和</i>
标记放在第一个[^[:space:]]
(非空格)字符子串周围,用于&
表示替换模式中的搜索词,无论该行是否缩进。
用于-E
启用 的sed
扩展正则表达式:
sed -E 's/[^[:space:]]+/<i>&<\/i>/' file
当使用/
分隔搜索和替换术语时,您需要/
在other 之前加上\
(如此处的第二个标签)。您可以通过使用分隔搜索术语和替换术语以外的字符来避免此额外步骤/
,只要该字符不出现在术语中即可。例如,使用逗号:
sed -E 's,[^[:space:]]+,<i>&</i>,' file
这是最短的路。
(代表模式的一次或多次出现)在普通(而不是)正则表达式+
中不起作用,但您可以使用(代表零次或多次出现)做同样的事情,只需多输入一点:-e
-E
*
sed -e 's,[^[:space:]][^[:space:]]*,<i>&</i>,' file