首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >嵌套条件搜索与就地替换

嵌套条件搜索与就地替换
EN

Stack Overflow用户
提问于 2018-11-22 08:51:20
回答 2查看 96关注 0票数 1

我是个新手。我有一份文件看起来是:

代码语言:javascript
复制
beans and celery  
beans and oatmeal  
beans and beans  
quinoa
<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>

我正在执行搜索并替换"fo“标签的位置。我想捕获标签的开头,以及"src“参数。请注意,src标签的位置因行而异!

我已经能够使用以下方法获得我想要的字段:

代码语言:javascript
复制
awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i}}' inventory.txt

我怎样才能就地替代这个呢?我还想在行的新内容中添加一个字符串。我试过:

代码语言:javascript
复制
awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") print $1 " " $i "misc stuff here"}}' inventory.txt

但是,它完全扰乱了结果字符串的顺序,我希望它的形式是:

代码语言:javascript
复制
<fo:external-graphic src="url(images/image1.png)" misc stuff here

PS1:进一步澄清我想要的结果:该文件包含字符串,如:

代码语言:javascript
复制
<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" height="auto" content-width="246px" content-height="322px"/>

我想对这些内容进行处理,并获得如下输出:

代码语言:javascript
复制
<fo:external-graphic src="url(images/image1.png)" _completely new stuff here, till end of string_ />

例如:

代码语言:javascript
复制
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M" />

我希望结果总是从以下方面开始:

代码语言:javascript
复制
<fo:external-graphic src="url(images/image1.png)"

然后是额外的东西,如:

代码语言:javascript
复制
age="25" sex="M" />

在最终输出中不需要原始字符串的其他部分。

PS2:我能把这些都打包成gsub吗?据我所知,gsub只提出了两个论点。我试着用一个复杂的表达式来表示替换论点,但它一直失败:

代码语言:javascript
复制
gawk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") gsub($0, "boy band"); {print}}}' inventory.txt > testres

PS3:这只是新手的观察,也许我错了。考虑一个包含以下内容的文件:

代码语言:javascript
复制
Donald Trump
Donald Duck
George Bush
Steve Austin

搜索以Donald开头的所有行的regexp是:

代码语言:javascript
复制
/^Donald/

如果我想用“兵营”替换所有"Donald“,我可以这样做:

代码语言:javascript
复制
gawk -i inplace '{ gsub(/^Donald/, "Barrack"); { print } }' FILENAME

如果我想要完全更改包含“”的所有行,我会这样做:

代码语言:javascript
复制
gawk -i inplace '{ gsub(/^Donald.*/, "Barrack"); { print } }' FILENAME

gawk和gsub似乎只替换了span或字符串的任何部分与给定的regexp匹配。因此,如果我想要完全改变整个行,我的regexp应该跨越整个行。

PS4:只是为了消除我所期望的解决方案的任何含糊之处。给定以下文件:

代码语言:javascript
复制
<fo:external-graphic width="auto" height="auto" content-width="36pt" src="url(file:/C:/Users/xxx/images/tip.svg)"/>
<fo:external-graphic width="6.3in" height="auto" src="url(images/image1.png)" content-width="246px" content-height="322px"/>
<fo:external-graphic src="url(images/image1.png)" width="6.3in" content-width="246px" content-height="322px"/>

我正在寻找一个awk/gawk解决方案,它将把这个文件替换为:

代码语言:javascript
复制
<fo:external-graphic src="url(file:/C:/Users/xxx/images/tip.svg)" age="25" sex="M" />
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>
<fo:external-graphic src="url(images/image1.png)" age="25" sex="M"/>

目标文件必须更改为

EN

回答 2

Stack Overflow用户

发布于 2018-11-22 08:56:34

您的尝试是正确的,但假设您的意图仅在以src开头的单词(即$i上)上添加,则只对该字段应用操作,并保留其他字段的原样。

代码语言:javascript
复制
awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) {if ($i ~ "src") $i = $i " misc stuff here"}}1' inventory.txt

部件$i = $i " misc stuff here"只在与regex条件匹配的字段上追加字符串。注意删除了print,并在末尾追加了{..}1。这基本上意味着根据{..}内部所做的修改重新构建整个行。由于我们只对某些字段进行修改,其他字段则保持不变。

如果您想重写以src开头的整个字段并附加一些字符串,请使用与gsub()匹配的正则表达式,并在以&表示的匹配文本之后追加字符串。

代码语言:javascript
复制
awk '/<fo:external-graphic.*/ {for (i=1; i<=NF; ++i) { if ($i ~ "src") gsub(/src=\"url([^"]*)\"/, "& new string", $i ) }}1' inventory.txt

从OP最近的编辑来看,OP似乎只希望在末尾添加带有新字符串的src字段。其余的字段似乎可以忽略不计。在GNU上使用match()有一个额外的优点,就是添加第三个参数来将捕获的组存储为

代码语言:javascript
复制
awk -v newstr="age=\"25\" sex=\"M\"" 'match($0, /^(<fo:external-graphic).*(src=\"url([^"]*)\").*(\/>)$/, arr){ print arr[1]" "arr[2]" "newstr""arr[4]  }' file

请注意,GNU awk直到4.1.2才进行适当的修改,您只需对其进行修改即可。

代码语言:javascript
复制
gawk -i inplace '{...}' inventory.txt

对于之前的版本,请使用临时文件。

代码语言:javascript
复制
awk '{...}' inventory.txt > tmpfile && mv tmpfile inventory.txt

或者,如果安装了moreutils,请使用sponge来关闭第一个命令的输出,并用最新的命令重新创建文件。

代码语言:javascript
复制
awk '{...}' inventory.txt | sponge inventory.txt

从关于这个问题的示例文本中,人们无法识别它是否属于某种标记语言(XML、HTML)。如果它是一种正确的语法感知语言,那么您应该使用一个知道语法的解析器。

票数 2
EN

Stack Overflow用户

发布于 2018-11-22 09:30:11

EDIT3:根据OP的新编辑,在这里添加了一段代码。

代码语言:javascript
复制
awk  '
/ width.*content-width.*src/{
  sub(/ width.*content-width.*src/," src")
  sub(/\/>$/," age=\"25\" sex=\"M\"&")
}
/src.*width/{
  match($0,/src[^)]*/)
  val=substr($0,RSTART,RLENGTH+2)
  sub(/src.*/,"")
  $0=$0 OFS val OFS "age=\"25\" sex=\"M\"/>"
}
1
'  Input_file

EDIT2:用于更改OP的PS3的完整行,请您试一试。

代码语言:javascript
复制
awk '/^Donald/{$0="new_line_value"} 1'  Input_file
new_line_value
new_line_value
George Bush
Steve Austin

编辑:自OP以来的已经更改了预期的输出,因此现在也按照该输出添加解决方案。

代码语言:javascript
复制
awk '/^<fo:external-graphic src=.*/ && match($0,/src=.*\)\"/){$0=substr($0,1,RSTART+RLENGTH) " new_value_bla_bla_here.. />"} 1' Input_file

请您试一试(因为您的预期输出不清楚,所以还没有进行彻底的测试)。

代码语言:javascript
复制
awk '
/^<fo:/ && match($0,/src=.*>/){
  $0=substr($0,1,RSTART-1) OFS "new_value_here.." OFS substr($0,RSTART+RLENGTH+1)
}
1
'  Input_file

在这段代码中,检查从<fo:字符串开始的一行,然后尝试从src=捕获字符串直到/ by match,并在这里用新的字符串替换捕获的文本。

如果您希望将输出保存到Input_file本身中,那么也可以在上面的代码中添加> temp_file && mv temp_file Input_file

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53427025

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档