Matheus Gontijo
Matheus Gontijo

Reputation: 1307

Does lookbehind work in sed?

I created a test using grep but it does not work in sed.

grep -P '(?<=foo)bar' file.txt

This works correctly by returning bar.

sed 's/(?<=foo)bar/test/g' file.txt

I was expecting footest as output, but it did not work.

Upvotes: 52

Views: 25728

Answers (4)

Podbrushkin
Podbrushkin

Reputation: 510

Powershell's -replace supports lookaheads:

(Get-Content -Raw file.tsv) -replace '(?<=\t)\\N(?=\t)','' | Set-Content file.tsv

It removes \N from empty tsv cells for 900mb file in 7s. But beware of possibly converted line breaks.

Upvotes: 0

jagprog5
jagprog5

Reputation: 131

sed doesn't support lookarounds but choose (I'm the author) does. It uses PCRE2 syntax.

For example:

$ echo "hello bar foobar" | choose -r --sed '(?<=foo)bar' --replace test
hello bar footest

It's speed is comparable to sed.

Upvotes: 1

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89629

Note that most of the time you can avoid a lookbehind (or a lookahead) using a capture group and a backreference in the replacement string:

sed 's/\(foo\)bar/\1test/g' file.txt

Simulating a negative lookbehind is more subtile and needs several substitutions to protect the substring you want to avoid. Example for (?<!foo)bar:

sed 's/#/##/g;s/foobar/foob#ar/g;s/bar/test/g;s/foob#ar/foobar/g;s/##/#/g' file.txt
  • choose an escape character and repeat it (for example # => ##).
  • include this character in the substring you want to protect (foobar here, => foob#ar or ba => b#a).
  • make your replacement.
  • replace foob#ar with foobar (or b#a with ba).
  • replace ## with #.

Obviously, you can also describe all that isn't foo before bar in a capture group:

sed -E 's/(^.{0,2}|[^f]..|[^o].?)bar/\1test/g' file.txt

But it will quickly become tedious with more characters.

Upvotes: 53

hwnd
hwnd

Reputation: 70732

GNU sed does not have support for lookaround assertions. You could use a more powerful language such as Perl or possibly experiment with ssed which supports Perl-style regular expressions.

perl -pe 's/(?<=foo)bar/test/g' file.txt

Upvotes: 49

Related Questions