views:

467

answers:

4

Hi,

I was just wondering if anyone could help out with how to do the following using vi.

I have a text file and it might contain something like

start of text file:
--something1.something2--
--anotherThing1.something2--
end of text file:

If I want to take this line and convert it by way of searching for anything matching the first occurrence of [A-Za-z0-9] copy that to the buffer then append it on the same line to before the first occurrent of --

start of text file:
--something1.something2.something1--
--anotherThing1.something2.anotherThing1--
end of text file:

Is there a single VI command to do this?

Cheers Ben

+5  A: 
:%s/--\([a-zA-Z0-9]*\).\(.*\)--/--\1.\2.\1--/gc

or without asking confirmation for every replace:

:%s/--\([a-zA-Z0-9]*\).\(.*\)--/--\1.\2.\1--/g

will produce:

--something1.something2.something1--
--anotherThing1.something2.anotherThing1--

from:

--something1.something2--
--anotherThing1.something2--

This is if you want to copy the first word after '--' up to first '.' and append '.' and word found before the last '--'.

Using vim.

RE COMMENTS:

Someone mentioned that it will not work when there are multiple words and so on. I tested it on the following:

start of text file:
--something1.something2.something3.something4.something5.something6--
--anotherThing1.something2.anotherThing3.anotherThing4.anotherThing5--
end of text file:

after replace with the above expression:

start of text file:
--something1.something2.something3.something4.something5.something6.something1--
--anotherThing1.something2.anotherThing3.anotherThing4.anotherThing5.anotherThing1--
end of text file:
stefanB
Remove the "c" from the end if you don't want to be asked to confirm each replacement.
Jon Grant
The /g modifier to the regex is not necessary. Your regex does not work if there are multiple occurances of --text.text-- on one line.
what do you mean by --text.text-- ... do you have example that fails?
stefanB
you guys are the bomb that is really great. I normally do the substitution a little differently.:g/--\([A-Za-z0-9]*\).\(.*\)--/s//--\1.\2.\1--
benjipete
really like the groups was not sure you could do it thanks for your help
benjipete
+1  A: 

Holy crap, in the time it took me to login to post that answer, you posted it and already got a comment!

%s/--\(\w*\)\.\(.*\)--/--\1.\2.\1--/g

--ab1.cd2..yz99-- -> --ab1.cd2..yz99.ab1--

Bashwork
I actually tested it first before posting ...
stefanB
+1  A: 

Try this:

%s:\([A-Za-z0-9]\+\)\(\..\+\)--:\1\2.\1--:g
Alan Haggai Alavi
A: 

Building on stefanB's solution but using negated character classes and the "very magic" setting, I arrive at the following substitution command:

:%s/\v--([^.]+)\.(.*)--/--\1.\2.\1--/

Depending on the exact requirements (what are allowed characters for "something1" and "anotherThing1") this might or might not be more correct.

One more thing to consider: all solutions posted so far assume that there is only one occurance of the "--text.someOtherText-- pattern per line. If this is not the case, the (.*) part of the pattern would have to be adjusted and the /g modifier is required.

I've actually tested with multiple segments like "--anotherThing1.something2.anotherThing1.anotherThing1.anotherThing1--" it will still add the first word before the last --
stefanB