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
:%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:
Try this:
%s:\([A-Za-z0-9]\+\)\(\..\+\)--:\1\2.\1--:g
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--
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.
Related
I have a requirement which I am sure I can do in vi (plenty of other solutions I am sure), and this is it.
I have a file that looks like this
1234 Some Text HERE rest of line
1235 Some Other Text HERE rest of line
What I want to do is delete text from, and including the word HERE to the end of the line, leaving me with this;
1234 Some Text
1235 Some Other Text
I have done search and replace things in vi, but am not sure how to do a search then run a command.
Any help, as always is greatly appreciated.
Thanks in anticipation
How about that:
:%s/HERE.*//
This pattern replaces the part of the line starting with HERE and replaces it with nothing.
The combination of d$ will delete from the cursor to the end of the current line. So if you're searching using the / command, it'll be...:
/HERE<enter>d$
As always, in vi there are many ways to skin this particular cat. As has already been stated, a simple solution to exactly this problem is:
:%s/HERE.*//
However, to answer your more general question:
I have done search and replace things in vi, but am not sure how to do a search then run a command.
you want the :g[lobal] command:
:[range]g[lobal]/{pattern}/[cmd]
Execute the Ex command [cmd] (default ":p") on the
lines within [range] where {pattern} matches.
This would actually be more long-winded for your exact example, but for tasks such as deleting lines that match a specific pattern, it is considerably more concise.
e.g. if you wanted to instead delete all lines that contain HERE, you would run:
:g/HERE/d
Factoid: this command form is the origin of grep's name: g/re/p, shorthand for global/{regex}/print.
This can be done using sed also:
sed "s/HERE.*//"
Example:
echo "this is a test HERE test" | sed "s/HERE.*//"
Result:
this is a test
Let's say this is my text:
this is my text this
is my text this is my text
my text is this
I would like to highlight all text except pattern and delete the highlighted text.
p.e. text: this must be the result.
text
texttext
text
I've found the code how to select all text except pattern:
\%(\%(.{-}\)\#!text\zs\)*
however I don't know how to delete all highlighted text.
This doesn't work:
:%s/\%(\%(.{-}\)\#!bell\zs\)*//
Can anyone help me?
Try this:
:%s/\(^\|\(text\)\#<=\).\{-}\($\|text\)\#=//g
Explanation:
\(^\|\(text\)\#<=\) # means start of line, or some point preceded by “text”
.\{-} # as few characters as possible
\($\|text\)\#= # without globbing characters, checking that we reached either end of line or occurrence of “text”.
Another way to do it:
Create a function that count matches of a pattern in a string (see :help match() to help you design that)
Use: :%s/.*/\=repeat('text', matchcount('text', submatch(0)))
Forgive me, because I'm not a vim expert, but wouldn't prepending the search with v find the inverse so that you could do something like this?
:v/pattern/d
I've implemented Benoit's clever regular expression as a custom :DeleteExcept command in my PatternsOnText plugin. It offers other related commands like :SubstituteExcept or :SubstituteInSearch, too.
OP's example would be
:%DeleteExcept /text/
Comparing that with #Benoit's explicit command (:%s/\(^\|\(text\)\#<=\).\{-}\($\|text\)\#=//g), it's a lot simpler.
I have a simple vim problem that Google hasn't managed to help me with. Any thoughts are appreciated.
I do the following search and replace:
:s/numnodes/numnodes1/g
On a file containing the following text:
numprocs=0
numnodes=0
I get
E486: Pattern not found
The position of the green square which indicates where I'd start typing is clearly above the pattern. I tried searching for other short phrases not involving regex, which are also present, which also fail. A simple /numnodes highlights matches as expected. Does anyone have any idea what might be the matter with vim?
Try :%s/searchphrase/replacephase/g
Without the % symbol Vim only matches and replaces on the current line.
try using this:
:%s/numnodes/numnodes1/g
I'v written a plugin where it comes to parsing a XML tag. The content inside the tag is indented and when i copy the parsed string into the file it's gettting like:
Example line
This is part of the parsed line
Thats goes one
End of line
What I want is to remove all spaces in front of these lines, the final text should be
Example line
This is part of the parsed line
Thats goes one
End of line
I've tried to use = but it doesn't work the way I want. How can I do that with minimal key strokes ?
To format a line to the left I use :left. Use this format an entire file:
:%le
A simple search/replace s/^\s*// should do the trick, but it's probably not the minimal version.
Personally I would visually select the lines with V, then use 99< to push the text as far left as it could go.
Just type d followed by w followed by j at the beginning of each line.
How about this:
:%s/^ *//
Or are you looking for a vim-script solution?
To remove initial spaces and tabs at specified line numbers (E.g. from lines 5 to 10),
:5,10s/^\s*//
Yet another way to achieve this is using the the normal command :h :normal-range
:%norm d^
This goes to column 0 in each line (%) and deletes (d) to the first non-white character(^).
This is slightly more to type as the accepted answer, but allows for easy extension if you have a more complex scenario in mind, such as additional un-commenting or so:
:%norm d^I#
Resulting in:
#Example line
#This is part of the parsed line
#Thats goes one
#End of line
The search/replace suggested by Lukáš Lalinský or the %le approach in the wikia page is probably the way I'd do it, but as another alternative you could also do:
:%< 99
As a quick way to shift the whole file (%) 99 times to the left.
Remove all consecutive spaces: :%s/ */ /g
It was useful to me to go from:
$screen-xs-min: 480px;
$screen-sm-min: 768px;
$screen-md-min: 992px;
$screen-lg-min: 1200px;
To:
$screen-xs-min: 480px;
$screen-sm-min: 768px;
$screen-md-min: 992px;
$screen-lg-min: 1200px;
I have an XML file like this:
<fruit><apple>100</apple><banana>200</banana></fruit>
<fruit><apple>150</apple><banana>250</banana></fruit>
Now I want delete all the text in the file except the words in tag apple. That is, the file should contain:
100
150
How can I achive this?
:%s/.*apple>\(.*\)<\/apple.*/\1/
That should do what you need. Worked for me.
Basically just grabbing everything up to and including the tag, then backreferences everything between the apple begin and end tag, and matches to the rest of the line. Replaces it with the first backreference, which was the stuff between the apple tags.
I personally use this:
%s;.*<apple>\(\d*\)</apple>.*;\1;
Since the text contain '/' which is the default seperator,and by using ';' as sep makes the code clearer.
And I found that non-greedy match #Conspicuous Compiler mentioned should be
\{-}
instead of "{-}" in Vim.
However, I after change Conspicuous' solution to
%s/.*apple>(.\{-\})<\/apple.*/\1^M/g
my Vim said it can't find the pattern.
In this case, one can use the general technique for collecting pattern matches
explained in my answer to the question "How to extract regex matches
using Vim".
In order to collect and store all of the matches in a list, run the Ex command
:let t=[] | %s/<apple>\(.\{-}\)<\/apple>\zs/\=add(t,submatch(1))[1:0]/g
The command purposely does not change the buffer's contents, only collects the
matched text. To set the contents of the current buffer to the
newline-separated list of matches, use the command
:0pu=t | +,$d_