regex sed -如何从字符串向上匹配到固定位置

wgx48brx  于 2023-08-08  发布在  其他
关注(0)|答案(4)|浏览(116)

理想情况下使用sed并给定输入

123456789
ABfooEFGH
MNOPfooYZ

字符串
我想匹配从foo开始到位置8结束的子字符串。
因此,如果我打算用bar替换该匹配,我需要输出

123456789
ABbarH
MNOPbarZ


我想象一个sed命令,如下所示

sed -E 's/foo.<8>/bar/' input.txt


其中.<8>是我虚构的语法,意思是“匹配固定位置8(包括8)以内的任何字符”

这是我的问题,下面的所有内容都是为了展示我的推理和我已经尝试过的内容。如果你赶时间的话,请根据上面的内容回答:)

我其实是打算在固定位置后再配更多的东西太,所以更喜欢

sed -E 's/foo.<8>[a-z]*/bar/' input.txt


虽然我不认为这会让答案复杂化所以我把它从我的例子中去掉了。
匹配字符串实际上是一个bash变量,而不是硬编码的foo,因此更像是

str="not foo"
sed -E 's/'"$str"'.<8>[a-z]*/bar/' input.txt


以下内容不正确

str="not foo"
len=${#str}
pos=8
chars=$((pos-len))
sed -E 's/'"$str"'.{'"$chars"'}[a-z]*/bar/' input.txt


因为我不知道$str会出现在每一行的什么位置--除了我可以假设它总是出现在固定位置$pos之前。
最后,所需的固定位置也将是一个bash变量,而不是硬编码的,尽管我不认为这会使答案复杂化。

anhgbhbe

anhgbhbe1#

假设目标总是在第8个位置之前结束,您可以使用图案空间和保持空间:

sed '/foo/{h;s/.\{8\}//;x;s/foo.*/bar/;G;s/\n//}' input

字符串
详情:

/foo/              # if "foo" exists in the line
{
    h;             # copy the pattern space to the hold space
    s/.\{8\}//;    # remove the first 8 characters (in the pattern space)
    x;             # exchange the pattern space and the hold space
    s/foo.*/bar/;  # replace "foo" until the end of the line with "bar"
    G;             # append the hold space to the pattern space
    s/\n//         # remove the newline (from the pattern space)
}


如果你必须处理少于8个字符的行,将\{8\}改为\{1,8\}

5f0d552i

5f0d552i2#

试试这个:

sed 's/.\{8\}/&\x0/;s/foo.*\x0/bar/;s/\x0//' input

字符串
它匹配(前)8个字符,并在它们后面追加一个\x0(null)字符作为标记。然后从foo替换到该标记(包括foo)。
如果这份声明
我可以假设它总是出现在固定位置$pos之前
表示foo的第二个o不在位置8之后,则可以缩短为

sed '/foo/s/.\{8\}/&\x0/;s/foo.*\x0/bar/' input


其仅在匹配foo的行上应用s替换命令。

qnzebej0

qnzebej03#

使用awk

$ pattern="foo"
$ replacement="bar"
$ awk -v p="$pattern" -v r="$replacement" 'BEGIN{OFS=""} {if (match($0,"foo")) {prefix=substr($0,0,8); suffix=substr($0,9,9); gsub(p".*",r,prefix); print prefix,suffix} else {print}}' file
123456789
ABbarH
MNOPbarZ

字符串
对于包含该模式的字符串,它创建两个变量prefixsuffix,然后从前缀中删除该模式后面的所有字符(如果有的话),并用替换项替换它们,最后打印这两个变量。

soat7uwm

soat7uwm4#

流处理模式下的Perl允许对匹配/^(.*foo)/的长度进行一些算术运算,这样你就可以调整每个foo后面要匹配的字符数:

perl -pe '/^(.*foo)/; $x=8-length($1); s/foo.{$x}/bar/' file

字符串

相关问题