【问题标题】:How to replace characters within a substring with sed or awk?如何用 sed 或 awk 替换子字符串中的字符?
【发布时间】:2020-02-18 19:51:33
【问题描述】:

我需要替换 HTML 文档中某些文件名(并且只有文件名)的特殊字符。我知道如何用trsed 替换整个 文本中的特殊字符,我知道如何用sed(例如's,src="\([^"]*\)",src="newprefixtofilename_\1"')用另一个给定字符串替换文件名,但我不确定sed 能否以某种方式匹配我在\1 中得到的字符?

如果sed 无法做到这一点,我该怎么做? awk?可能可以隔离以src= 为前缀的" 分隔字符串,并仅在这些字符串上使用gsub。我可以假设src= 仅出现在标签中(因此没有“真正的”html 解析),并且每个文件行只有一个字符串匹配。

示例输入行:

  <img src="spécial.png"> Spécial
  <img src="piètre.png"> Some text including "piètre"

仅在文件名中将[éî] 替换为[ei] 的所需输出:

 <img src="special.png"> Spécial
 <img src="pietre.png"> Some text including "piètre"

【问题讨论】:

  • sed 和 awk 都不是为解析 HTML 而设计的。首先,找到合适的工具
  • 你能举一个输入和期望输出的例子吗?
  • @oguzismail 感谢您的评论,但这是脚本中的 1 行,最好在 bash 中完成。
  • 为什么不sed 's,src="spécial.png",src="special.png",'
  • @KamilCuk 因为我有各种非常不同的文件名...

标签: bash sed replace


【解决方案1】:

您不能直接使用sed 执行此操作(不知道 awk,但是)。首先,您需要创建一个辅助文件,在其中将每个字符替换为 UTF8 字符,而不是解析和替换差异。

我强烈建议先在测试数据上尝试一下。

# Translate non UTF8
$ iconv -f utf-8 -t ascii//translit files.html > tmp.txt

# Create arrays (IFS if files have spaces, otherwise redundant)
$ IFS=$'\n'
$ FROM=($(diff files.html tmp.txt | grep '^<.*<img' | sed -r 's/.*src="([^"]*)".*/\1/'))
$ TO=($(diff files.html tmp.txt | grep '^>.*<img' | sed -r 's/.*src="([^"]*)".*/\1/'))

# Rename files (mv spécial.png special.png)
$ for ((i=0; i < ${#FROM[@]}; i++)); do mv "${FROM[$i]}" "${TO[$i]}"; done

# Change html src attributes
$ for ((i=0; i < ${#FROM[@]}; i++)); do sed -i "s/${FROM[$i]}/${TO[$i]}/" files.html; done

# End result
$ cat files.html 
<img src="special.png"> Spécial
<img src="pietre.png"> Some text including "piètre"

【讨论】:

  • 感谢 Bayou,这很聪明,而且看起来非常健壮。为什么在“创建数组”部分的 grep 中使用 '>' 和 '
  • 不客气。通过 grepping &gt;&lt;,您可以过滤掉一个文件相对于另一个文件的差异。因此,grep &lt; 给出了 files.html 和 grep &gt; 与 tmp.txt 中的区别。如果您的文件中有空格,请在创建数组之前使用IFS=$'\n'
  • 测试和批准。
【解决方案2】:

说明要求:仅在 src="..." 标记内替换特殊字符 (é->e, î->i)。

假设 XML 文件的格式合理(更具体地说,完整的 IMG 标记在一行上),可以使用 's' 命令替换每个特殊字符。

First line é->e, second line î->i
sed -e 's,src="\([^"]*\)é\([^"]*"\),src=\1e\2,g' \
    -e 's,src="\([^"]*\)î\([^"]*"\),src=\1i\2,g'

上述解决方案不会处理多次具有相同特殊字符的 src。 (例如,src-“xîzîtîFi.png”。如果这是一个问题,并假设在下面的示例中接受少量重复 92,那么

   # é->e 
sed -e 's,src="\([^"]*\)é\([^"]*"\),src="\1e\2,g' \
  -e 's,src="\([^"]*\)é\([^"]*"\),src="\1e\2,g' \
  -e 's,src="\([^"]*\)é\([^"]*"\),src="\1e\2,g' \
  -e 's,src="\([^"]*\)î\([^"]*"\),src="\1i\2,g' \
  -e 's,src="\([^"]*\)î\([^"]*"\),src="\1i\2,g' \
  -e 's,src="\([^"]*\)î\([^"]*"\),src="\1i\2,g'

我确信有可能使用标签/分支更有效地执行上述替换以处理无限数量的特殊字符。

重命名文件 另一个问题可以利用“sed”音译命令。比如:

for file in FILELIST ; do
  new_name=$(echo $file | sed -e 'y/éî/ei/')
  if [ "$file" != "$new_name] ; then
    mv $file $new_name
  if
done

【讨论】:

  • more than once - 你可以循环直到替换为t。基本上你做: loop; /src="\([^"]*\)é\([^"]*"\)/{ s//src="\1e\2/g; t end; b loop; } : end;
猜你喜欢
  • 1970-01-01
  • 2015-01-13
  • 2017-02-08
  • 2010-12-07
  • 1970-01-01
  • 2012-12-21
相关资源
最近更新 更多