在字符第 N 次出现后替换特定文本

在字符第 N 次出现后替换特定文本

我想将下面文件中的数字替换为#Mi.

仅适用于第 10 次出现"(双引号)之后的数字

输入文件

"col1" "col2" "col3" "col4" "col5" #Mi #Mi #Mi #Mi #Mi #Mi 1002.47 1018.81 1016.68 
"col1" "col2" "col3" "col4" "col5" #Mi #Mi #Mi #Mi #Mi #Mi 501.24 509.41 508.34 
"col1" "col2" "col3" "col4" "col5" #Mi #Mi #Mi #Mi #Mi #Mi 55.69 56.6 56.48 

输出文件

"col1" "col2" "col3" "col4" "col5" #Mi #Mi #Mi #Mi #Mi #Mi #Mi #Mi #Mi 
"col1" "col2" "col3" "col4" "col5" #Mi #Mi #Mi #Mi #Mi #Mi #Mi #Mi #Mi 
"col1" "col2" "col3" "col4" "col5" #Mi #Mi #Mi #Mi #Mi #Mi #Mi #Mi #Mi

答案1

sed

<your-file sed '
  s/"/"\
/10;                          # add a newline after the 10th "
  h;                          # save a copy
  s/.*\n//;                   # remove everything before the newline
  s/[0-9.]\{1,\}/#Mi/g;       # replace numbers with #Mi
  G;                          # append saved copy
  s/\(.*\)\n\(.*\)\n.*/\2\1/; # put it back together'

使用perl(5.14.0 或更高版本的r替换标志):

perl -pe 's{(.*?"){10}\K.*}{$& =~ s/[\d.]+/#Mi/gr}e' < your-file

对于旧版本(但至少仍为 5.10.0 \K):

perl -pe 's{(.*?"){10}\K.*}{($r = $&) =~ s/[\d.]+/#Mi/g; $r}e' < your-file

对于更旧的版本:

perl -pe 's{((?:.*?"){10})(.*)}{
  $l = $1; ($r = $2) =~ s/[\d.]+/#Mi/g; $l.$r}e' < your-file

同时数字是一个或多个数字的任意序列 或.。您可能需要细化模式以避免它匹配类似127.0.0.1....任何地方的内容,以防此类情况可能出现在第 10 个之后的输入 "。例如,在 中perl,可能是(?<!\S)\d+\.\d+(?!\S):数字-点-数字,前面和后面都没有非空格。

在你的样品上,甚至

perl -pe 's/(?<!\S)\d+\.\d+(?!\S)/#Mi/g' < you-file

就足够了,因为 10号 之前的部分"没有这些数字-点-数字不被非空白包围。这一切都归结为您想要替换的内容以及您输入的内容中可能会发生什么想要被替代。

答案2

使用perl我们按如下方式进行。用 a 标记第 10 次出现的双引号,\n因为它永远不会出现在行中,因为它会被选项剥离-l


$ perl -lpe '
    s/((?:.*?"){10})/$1\n/;
    s/(?<!\S)\d+\.\d+(?!\S)(?!.*\n)/#Mi/g;
    tr/\n//d;
' file

$ d='[[:digit:]]' f="$d$d*[.]$d$d*" r='#Mi' 
$ sed -Ee "
    s/\"/&\n/10
    :loop
       s/(\n.*\s)$f(\s|\$)/\1$r\2/
    t loop
    s/\n//
" file

相关内容