替换除 \N 之外所有出现的 \

替换除 \N 之外所有出现的 \

我有一个这样的文件:

1,2,subjects,\mat\hs,unix\,\Nato,\N,123,\N

我想用 # 替换所有出现的 \,除了 \N,这样输出如下所示:

1,2,subjects,#mat#hs,unix#,#Nato,\N,123,\N

我正在尝试编写一个 sed 命令,它看起来像-

sed -e 's@\\([^N])@#\1/g' filename

但是对于 ex 开头有 \N 的所有值,这都会失败。\Nato在上面的例子中。

有人可以帮我找出满足我要求的 sed 命令(正则表达式)吗?

答案1

我不太精通sed。但这可以通过perl使用正则表达式环视轻松完成:

perl -pe 's/\\(?!N\b)/#/g' your_file_here

这会将修改后的文件打印到标准输出。要进行替换,您可以执行以下操作:

perl -pi -e 's/\\(?!N\b)/#/g' your_file_here

基本上,这会将任何后面未跟的反斜杠N\b(单词边界处的字符 N)替换为#

编辑

如果您绝对确定您的条目是用逗号分隔的,则可以执行此操作来覆盖\N单词末尾的情况(如SOLEM\N您提供的示例中所示):

perl -pe ' s/\\/#/g; s/(\A|,)\s*#N\s*(\Z|,)/$1\\N$2/g;' your_file_here

它只是用散列标记替换任何反斜杠,然后#N在两个逗号之间、字符串开头和逗号之间或逗号和字符串结尾之间查找找到的内容。

答案2

$ echo '1,2,subjects,\mat\hs,unix\,\Nato,\N,123,\N' \
  | sed -r -e 's@\\([^N]|N[^,])@#\1@g'
1,2,subjects,#mat#hs,unix#,#Nato,\N,123,\N

编辑对于 \N 作为单词大小写的一部分:(参见注释)

$ echo '1,2,subjects,\mat\hs,unix\,\SOLEM\N,\N,123,\N' \
  | sed -r -e 's@,\\N$@,:SINGLE_N_PLACEHOLDER:@g' \
           -e 's@^\\N,@:SINGLE_N_PLACEHOLDER:,@g' \
           -e 's@,\\N,@,:SINGLE_N_PLACEHOLDER:,@g' \
           -e 's@\\@#@g' \
           -e 's@:SINGLE_N_PLACEHOLDER:@\\N@g'
1,2,subjects,#mat#hs,unix#,#SOLEM#N,\N,123,\N

这是丑陋且不可靠的(占位符字符串需要是唯一的,如果该模式出现在文本中,将停止工作),但我没有找到一种工作方法来使 sed 使用 PCRE/Perl 支持断言的方式。

你可以像这样缩短它:

$ echo '1,2,subjects,\mat\hs,unix\,\SOLEM\N,\N,123,\N' \
  | sed -r -e 's@\\@#@g' \
           -e 's@(,|^)#N(,|$)@\1\\N\2@g'
1,2,subjects,#mat#hs,unix#,#SOLEM#N,\N,123,\N

但在本例中,single#N是不得出现在字符串中的占位符。

答案3

sed -e 's@\\\([^N]\|\(N[a-zA-Z]\|$\)\)@#\1@g' your_file_here

解释:替换所有\后面的

  • 没有什么N
  • N后跟任何字母[a-zA-Z](如果需要的话可以扩展)
  • 行结束

with#和其余的匹配模式。

答案4

$ echo '1,2,subjects,\mat\hs,unix\,\Nato,\N,123,\N'   | 
         sed -r -e 's/\\N/XELI/g' | 
         sed -e 's/\\/#/g' | 
         sed -e 's/XELI/\\N/g'
1,2,subjects,#mat#hs,unix#,\Nato,\N,123,\N

我发现将其拆分更具可读性:

  • 将 \N 替换为一些不出现的字符,
  • 然后将/替换为#
  • 并将 /N 替换回来

相关内容