sed:替换另一个模式中的模式

sed:替换另一个模式中的模式

我想用这样的值替换$SOME_TEXT_HERE$这样的值:@some.text.here@ 即:

  1. 将文本更改为小写
  2. $用。。。来代替@
  3. 将下划线替换为点

初始字符串中可能存在任意数量的不相关文本。可以替换任意数量的美元分隔文本。以美元分隔的文本可以由一个或多个大写单词组成,并用下划线分隔。

我知道如何执行步骤 1 和 2。我想知道如何将步骤 3 限制为美元符号内的内容。

好的,举个例子:

从: Lorem $IPSUM$ $dolor_sit_amet _ _ _ consectetur $ADIPISICING_ELIT$ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ $ET_DOLORE_MAGNA_ALIQUA$

到: Lorem @ipsum@ $dolor_sit_amet _ _ _ consectetur @adipisicing.elit@ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ @et.dolore.magna.aliqua@

我已经做到了这一点: echo 'Lorem $IPSUM$ $dolor_sit_amet _ _ _ consectetur $ADIPISICING_ELIT$ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ $ET_DOLORE_MAGNA_ALIQUA$ ' |sed -e 's/\$\([A-Z]\+_\?\)\+\$/\L&/g' -e's/\$\(\([a-z]\+_\?\)\+\)\$/@\1@/g'

这使: Lorem @ipsum@ $dolor_sit_amet _ _ _ consectetur @adipisicing_elit@ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ @et_dolore_magna_aliqua@

不知道如何迭代匹配的组结果以获取 @ 符号中的所有单词。始终获取最后的匹配结果。

答案1

使用 Perl:

$ cat file
Lorem $IPSUM$ $dolor_sit_amet _ _ _ consectetur $ADIPISICING_ELIT$ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ $ET_DOLORE_MAGNA_ALIQUA$
$ perl -pe 's/\$([[:upper:]_]+)\$/"@" . lc $1 =~ tr[_][.]r . "@"/eg' file
Lorem @ipsum@ $dolor_sit_amet _ _ _ consectetur @adipisicing.elit@ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ @et.dolore.magna.aliqua@

这里使用的 Perl 表达式是

s/\$([[:upper:]_]+)\$/"@" . lc $1 =~ tr[_][.]r . "@"/eg

这是一种应用于由首字母$后跟一个或多个大写字符或下划线,后跟另一个$字符组成的子字符串的替换。

$1替换模式是一个 Perl 表达式,它使用运算符将​​与模式 () 中的括号组匹配的子字符串中的所有下划线更改为点tr,然后使用 来将结果小写lc。然后在结果@前面和后面添加字符。

它是表达式/e的标志s///,使 Perl 将替换文本视为 Perl 表达式而不仅仅是文本。使用该标志对所有匹配重复替换/g

答案2

如果输入存储在shell$string中的变量中zsh,您可以执行以下操作:

set -o extendedglob
string=${string//(#b)\$([A-Z]##(_[A-Z]##)#)\$/@${(L)match[1]//_/.}@}

perl与相同

string=$(
  printf '%s\n' "$string" | perl -pe '
    s{\$[A-Z]+(_[A-Z]+)*\$}{lc$& =~ y/_$/.@/r}ge'
)

或者:

string=$(
  printf '%s\n' "$string" | perl -pe '
    s{\$[A-Z]+(_[A-Z]+)*\$}{$& =~ y/A-Z_$/a-z.@/r}ge'
)

不同之处在于,它perl在字节级别工作(在基于 ASCII 的系统上需要 ASCII 编码),而zsh在字符级别工作(当字节无法解码为字符时,则回退到字节),具体取决于区域设置的编码。如果$string以换行符结尾,则行为也会有所不同,因为命令替换会删除它们。

答案3

与 GNU sed:(如你所愿sed

$ sed -E 's/\$([A-Z]+([A-Z]*_)*[A-Z]+)\$/@\L\1@/g;s/@([a-z]+)_/@\1./g;s/_([a-z]+)@/\.\1@/g; :X s/(\.[a-z]+)_/\1\./g; tX'

输出 :

$ echo 'Lorem $IPSUM$ $dolor_sit_amet _ _ _ consectetur $ADIPISICING_ELIT$ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ $ET_DOLORE_MAGNA_ALIQUA$' | sed -E 's/\$([A-Z]+([A-Z]*_)*[A-Z]+)\$/@\L\1@/g;s/@([a-z]+)_/@\1./g;s/_([a-z]+)@/\.\1@/g; :X s/(\.[a-z]+)_/\1\./g; tX'
Lorem @ipsum@ $dolor_sit_amet _ _ _ consectetur @adipisicing.elit@ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ @et.dolore.magna.aliqua@

答案4

另一个稍微短一点的 GNUsed

sed -E "s/\\\$([A-Z_]+)\\\$/@\L\1@/g; :X s/(@[a-z.]+)_/\1./; tX" file

假设这@不会在您的源中自然发生,并且$仅在最初的情况下发生[A-Z_]

Lorem $IPSUM$ $dolor_sit_amet _ _ _ consectetur $ADIPISICING_ELIT$ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ $ET_DOLORE_MAGNA_ALIQUA$
Lorem @ipsum@ $dolor_sit_amet _ _ _ consectetur @adipisicing.elit@ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ @et.dolore.magna.aliqua@

这对您的示例来说没问题,但如果您使用$BLAH_BLAH$blah_->@blah.blah@blah.而不是,则会失败@blah.blah@blah_

编辑重新 @Quasimodo 评论+->*在第二个sed

sed -E "s/\\\$([A-Z_]+)\\\$/@\L\1@/g; :X s/(@[a-z.]*)_/\1./; tX" file

Lorem $_IPSUM$ $dolor_sit_amet _ _ _ consectetur $ADIPISICING_ELIT$ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ $ET_DOLORE_MAGNA_ALIQUA$
Lorem @.ipsum@ $dolor_sit_amet _ _ _ consectetur @adipisicing.elit@ sed do $EUISMOD_TEMPOR INCIDIDUNT_UT_LABORE$ @et.dolore.magna.aliqua@

相关内容