How would I do something like the following in vim?
:1,/time s/import/new/g
What I am trying to do is:
- `:1,` from line 1...
- `/time` until the (first) match of the word 'time'
- `s/import/new/g` substitute the word 'import' with the word 'new'
Your syntax is almost correct. You need to use a second slash after your pattern to distinguish the end of your pattern from what comes next. So it would look like this:
:1,/time/ s/import/new/g
You want to use the search offset feature.
This command excludes the line containing 'time'
1,/time/-1s/import/new/g
The -1 here means 1 line up from the first line containing 'time'.
:help search-offset
Related
I have a text file in which many lines contain twice the symbol =, as in:
Animals:
clown=fish=vertebrate
cow=mammal=vertebrate
bug=insect=invertebrate
slug==snail
etc
I want to delete everything that is after the second = on each line only if the two = are not together, resulting in:
Animals:
clown=fish
cow=mammal
bug=insect
slug==snail
etc
How I can I do this?
I guess search for the second occurence of =, then select all results, then select until the end of line, then delete, but most of these steps I couldn't find a easy way to do.
This should be enough:
%s/=[^=]\+\zs=.*//
The interesting part is \zs. Look for it in the docs via :help \zs.
Beside that, I'm matching an equal sign (the first =) followed by 1 or more (\+) characters other than the equal sign ([^=]), followed by another equal sign.
Press : to go to command mode, then run this:
%s/\(\w\+=\w\+\).*/\1/g
Explanation: in entire file (%) substitute line with result from \w\+=\w\+ search pattern (one equals sign, surrounded by non-zero-length words-characters.
Since this will only match on lines where the first = is surrounded by word-characters, it won't apply to lines like slug==snail
One option is to use :normal
:%norm f=lf=D
This uses f to find the = character move to left, then search for another = using f before deleting with D. If an error occurs then that line is skipped
From Drew Neil's fantastic book "Practical Vim" I learned what you can do with the :g command. However, there is one expression I don't get.
:g/{/ .+1,/}/-1 sort
This sorts all lines between braces in the file alphabetically. The general form of this command is
:global/{pattern}/[cmd]
, with [cmd] consisting of [range] [cmd]. I get that the search pattern is the starting point, so :g/{/is clear. Then follows the range .+1,/}/-1, with . being the current line (i.e. every line matching the pattern { ), +1 adding a one-line offset, , separating the start of the range from the end, /}/ saying "until the closing brace" and -1 subtracting one line to match only the inner contents of the braces.
What I don't get is the /}/ part. What are the slashes needed for? Why is it not possible to just write }?
EDIT:
From Vimhelp 10.3 I now know that /}/is the search pattern used for the upper range boundary. Which leaves me still confused about the second / here. So the updated question is: Why do I need the second / before -1?
With ranges, the /.../ are always needed to tell Vim: this is a pattern, search for the next match and position the cursor there; that's where I want to start/end the range. If you look at :help :range, a literal } is not allowed there; Vim wants a line number, or a symbol representing such, a mark, or a search pattern. The only allowed variation is ?...? for an upwards search.
When you try out your suggested variant, you'll get
E492: Not an editor command: .+1,}-1 sort
Another way to motivate this is by abstracting from the concrete { ... } delimiters. Imagine how the range would look if you wanted a range inside foo ... bar. What if the range were 000 ... 999; Vim would not be able to differentiate between a literal number range (line 999) and the search (next line that contains 999).
I have a list of products to place on a rails seed and I would like to instead of put brackets one by one on the list with a command place the brackets on the whole list?
for example:
1. Dakine
2. Dale of Norway
3. Dan Post
1. ["Dakine"],
2. ["Dale of Norway"],
3. ["Dan Post"],
I searched on the help but did not find any about. Thanks.
You can record a macro in Vim and repeat that.
If you are on number 1, you can do following:
qqf a["Esc$a"],Esc0jq
Explanation:
qq: Start recording macro in register q
f: Go to first space character
a: : Insert after (the space character from above)
\[": Insert those characters
Esc: Back to normal mode
$: Go to end of line
a: Insert after (end of line)
"],: Insert the characters
Esc: Back to normal mode
0: Jump to start of line
j: Go down one line
If you have 100 such lines, you can do 100#q to achieve your result.
With vim substitute command:
:%s/.*/["&"]/
If you don't want to operate on all lines, then select the ones you want to transform or note the related line numbers, and then type :s/..... without the %. You'll see actually :'<,'>s this range represent the visually selected lines, and vim adds it automatically in visual mode.
On Atom you can enable the find to use Regex in the search(there is a button next to the search field)
Then you can search for something like (^.*$) to get every line separated by groups and in the Replace field you use ["$1"],. The $1 represents the value matched by the Regex.
Then just do a Replace All and remove the last comma in your list if needed.
I have a substitute command that captures and displays submatch() values in the replacement string. But I have another line of information that I want to parse below this line. That line is always the first line after an empty line, though the number of lines TO that empty line varies. For example:
The first important line I want to capture is here
Stuff I don't want.
A few more lines of stuff I don't want...
Second line I want to capture.
This pattern repeats a hundred or so times in a document. I can substitute "The First Important Line" fine, but shouldn't that search pattern include a way to jump down to the first empty line and then pick up the next "Second line I want to capture." ?? I could then place the contents of that second line into submatch parenthesis and substitute them where needed (right?).
If so, I cannot discover the way to extend the first search pattern to capture the "Second line" Suggestions or correcting my approach would be greatly appreciated.
Someone has already dealt with a similar problem. Below I provide their solution and the detailed description.
/^\nF\d\_.\{-}\_^\n\zs.*/+
It means "Find a block of lines that start with F and a digit,
then scan forward to the next blank line and select the line after that."
Part of regex
Meaning
^\n
Matches the start of a line, followed by a newline - i.e a blank line
F\d
The next line starts with an F followed by a digit
\_.\{-}
\_. is like ., but also matches newline. \{-} matches the minimum number of the preceeding \_.. (If I were to use * instead of \{-}, it would match to near the end-of file.)
\_^\n
Matches a blank line. \_^ is like ^, but ^ only works at the start of a regular expression.
\zs
When the match is finished, set the start of match to this point. I use this because I don't want the preceding text to be highlighted.
.*
Matches the whole line.
The + after the regular expression tells Vim to put the cursor on the line after the selection.
I think I read about offsets, but I can't find the bit in the help that is relevant right now. As such, my other solution would be to record a macro to do what you want:
qa/[Your pattern]<CR>jddq
You could then execute this macro with #a and repeat with ##; or run it a lot of times (e.g., 999#a).
I know in VIM how to search a string and delete the text till the start/end of line but I would like to know if it is also possible to delete all text in line before or after highlighted search pattern.
If you want to do this across all lines and don't want to retype your search term I'd suggest the following:
:%s/.*\ze<Ctrl-r>///
What this does is:
%s/: substitute across all lines in a file
.*: match any character
\ze: end matching so the rest of the pattern is not substituted
<Ctrl-r>/: insert text from the '/' register (which is the search register)
//: replace with nothing
Edit: Forgot about the after part. My suggestion to remove both at the same time would be:
:%s/.*<Ctrl-r>/.*/<Ctrl-r>//
To delete the text before FOO on the same line:
:s/^.*\(FOO\)/\1/
From beginning of line to the beginning of highlighted search pattern: 0dn
From after end of highlighted search pattern to the end of line: $N//e<Enter>lD
These will work in most of the cases.
I can't comment on other answers, so I answer here, but I am referring to the answer from xofon:
Just add a '%' in the command line, which would make do for all lines in a file.
delete all chars after ']' in all lines
:%s/\(\]\).*$/\1/
delete all chars before ' -- ' in all lines in a file
:%s/^\( -- \).*/\1/
To delete all text in the line line both before and after the search match you could also do:
:g//norm gnd0PlD
This executes normal mode commands on all lines that match the last search pattern. The commands are gn to select the match, d to delete it, 0P to paste it at the beginning of the line, l to move to the left (after the text that was just pasted) and D to delete until the end of the line. I'm given to understand gn is a fairly recent addition to vim, so YMMV.