Alfwed
Alfwed

Reputation: 3282

Replace a char within a pattern with sed

I'm trying to change to migrate my php code using ZF1/PEAR convention to namespaces.

So I want is to change

$locale_test = (new ACME_Common_Factory())->createLocale(ACME_Common_Enum_Civility::MR);

to

$locale_test = (new \ACME\Common\Factory())->createLocale(\ACME\Common\Enum\Civility::MR);

I've tried using the following sed program (which would work for lines containing only 1 class name)

sed -r '/ACME/{h;s/ACME_.*$//1;x;s/^.*(ACME.*)$/\\\1/;s/_/\\/g;x;G;s/\n//1}'

But it actually does little more than

sed -r '/ACME/s/_/\\/g'

I would prefer a solution using sed or awk (just for the sake of improving my cli skill) but any other solution will do.

Upvotes: 2

Views: 78

Answers (4)

potong
potong

Reputation: 58430

This might work for you (GNU sed):

sed -r ':a;s/(ACME[a-zA-Z\\]*)_/\1\\/;ta;s/ACME/\\&/g' file

Upvotes: 1

Alfwed
Alfwed

Reputation: 3282

I've finally found an answer inspired by @Wintermute

sed -r ':a s/(ACME[^;:\(]*)_([^;:\(]+)/\1\\\2/g; ta' file

Upvotes: 0

Wintermute
Wintermute

Reputation: 44043

Spaces as well as most special characters (but, crucially, not _) end a word, so I believe the word boundaries should serve well to identify class names. So, using GNU sed:

sed 's/\>/\n/g; :a s/\<\(ACME[^\n]*\)_\([^\n]*\)/\1\\\2/; ta; s/\<ACME/\\&/g; s/\n//g' filename

This works as follows:

s/\>/\n/g

puts newlines after closing word boundaries. We use this later to match (sort of) non-greedily. After this step, your line becomes

$locale_test
 = (new
 ACME_Common_Factory
())->createLocale
(ACME_Common_Enum_Civility
::MR
);

This leaves us with an easy way to identify names in the ACME namespace: \<ACME[^\n]*, and to identify names in the ACME namespace that contain an underscore: \<ACME[^\n]*_[^\n]*. We can use this to find underscores in ACME names and replace them one by one:

:a                                      # jump label for looping
s/\<\(ACME[^\n]*\)_\([^\n]*\)/\1\\\2/   # Attempt replacement
ta                                      # if it happened, go back to a.

After that, it's just

s/\<ACME/\\&/g

To put the \ in front, and

s/\n//g

To remove the newline markers we put there.

Mind you, I suspect that this would be easier in Perl.

Upvotes: 1

Jerome B
Jerome B

Reputation: 1

What about this ?

sed -r -e '/ACME_[^\(:]*/s/_/\\/g' -e 's/(ACME\\)/\\\1/g'

Upvotes: 0

Related Questions