How to get variable's value in this loop in vim - vim

I am trying to filter for multiple words using a loop but following is not working:
function! Myfilter (...)
for s in a:000
v/s/d
endfor
endfunction
It deletes all lines that do not contain the letter s rather than the value of s. How can I get value of s in statement v/s/d?

Deletes all lines other than those that contain all of the function's arguments
function! Myfilter0 (...)
exec 'v/\(.*' . join(a:000, '\)\#=\(.*') . '\)\#=/d'
endfunction
Example buffer
word1 beta word2
a word1 b word2 c
a word2 b word1 c word3 d
a word2 b word3 c word1 d
word1 delta
epsilon
Example function call
:call Myfilter("word1", "word2", "word3")
Example result
a word2 b word1 c word3 d
a word2 b word3 c word1 d
Note
Uses regex lookahead to match words in any order. This is what the example regex looks like after substitution and without the escape characters for clarity:
:v/(.*word1)#=(.*word2)#=(.*word3)#=/d

The :execute command is designed precisely for this task of
evaluating an expression and executing it as an Ex command:
exec 'v/' . s . '/d'

A much more efficient solution would be to compose a regex from your parameters, and to use it to remove non matching lines.
exe 'v/\('.join(a:000, '\|').'\)/d_'

Related

Copy and mark more than one line at once in notepad++

I have a big text file in which I search for lines I need to delete. I manually copy one line than put the mark button and repeat it again, I want to know if it possible to put all lines or at least more than one and mark it all? Maybe something in this way - word1>word2>word3 ets I don't know all combinations sorry
All words (lines) are unique so recording a marco is not a solution.
My text
word1
word2
word3
word4
word5
word2
word5
word4
I need to mark lines - word1, word2, word5
I do it manually one by one but I want to mark them all at once, maybe there is a regex for this I'm not sure like [word1, word2, word5] in the Find what area
If the number of words is not too big, you can do:
Ctrl+M
Find what: \b(?:word1|word2|word5)\b
TICK Match case
Mark all
Explanation:
\b # word boundary
(?: # non capture group
word1 # word1
| # OR
word2 # word2
| # OR
word5 # word3
) # end group
\b # word boundary
Screenshot:

Remove all one character words in string EXCEPT 'a' 'i' and 'o'

I'm trying to parse a file with the single quotes removed, leaving behind some random 's's and whatnot.
So far I've tried:
echo "a b c d e f g h i o omgifack" | grep -o '[^bcdefghjklmnpqrstuvBCDEFGHJKLMNPQRSTUV]\{2,\\}'
echo "a b c d e f g h i o omgifack" | tr -d '[bcdefghjklmnpqrstuvwxyzBCDEFGHJKLMNPQRSTUVWXYZ]'
The example I based these off of:
echo "a b c d e f g h i o omgifack" | grep -o '[a-z]\{2,\\}'
Desired output:
>a i o omgifack
I can't seem to figure it out, but I'm sure I'm missing something obvious. Open to solutions using awk, sed, tr, grep... anything that works. Thanks!
I'd probably use something like
echo "a b c d e f g h i o omgifack" | grep -wo '[[:alpha:]]\{2,\}\|[AIOaio]'
a
i
o
omgifack
This will isolate all whole words (because of -w) that are either more than two letters long (that's the [[:alpha:]]\{2,\} part) or one of [AIOaio].
Note that if the text contains umlauts or accented characters (such as ä, é, ß etc.), [[:alpha:]] does include those iff grep is run under a locale that recognizes them as part of its alphabet.
This might work for you (GNU sed):
sed 's/\b[^aio ]\b \?//Ig' file
Remove any singleton characters which are not a,i or u (upper or lower case) followed by a possible space.

How can I count the amount of five letter words in a txt file using grep?

I'm not very good at linux, and am trying to use grep to count five letter words.
You can use:
grep -o -w "\w\{5\}" your_file | wc -w
With -o only matched words will be printed, -w denotes that regex is searched as a word, \w\{5\} - regex string itself (matches 5 continuous word characters). So, with your_file containing
word1 word2 word3
long_word 123 word4
Output of grep -o -w "\w\{5\}" your_file will be
word1
word2
word3
word4
Piped wc -w just counts this.
Note: If you don't want to match all alphanumeric characters - replace \w meta-character by something more specific. For example [a-z] - lowercase English letters.
This gnu awk (due to mulitple characters in Record Selector) does count how many word have 5 letters. It does ignore ., etc.
awk -v RS="[ .,?!]|\n" 'length($0)==5 {a++} END {print a}' file
Use the c flag to count, look for patterns containing five characters:
$ cat file
some text file containing many words and sentences.
$ tr ' ' '\n' < file | grep -c '^[ \t]*[a-zA-Z]\{5\}[ \t]*$'
1

Writing text blocks using nested iteration in Vim

Let's say I'd like to write a 5x5 text block, such as
aaaaa
aaaaa
aaaaa
aaaaa
aaaaa
And I want to do it using nested iteration.
In pseudocode it would look like
do five times ((do five times (type 'a')) change line)
So my first guess was to simply convert that as
5 ((5 (i a esc)) enter)
But I can't do that, because Vim doesn't support use of parentheses for specifying execution order. And simply typing
5 5 i a esc enter
will of course not work, since that will just produce a single line with 55 'a's and a newline.
So my question is: Is there a way to write text blocks using nested iteration in Vim? I know that there are other ways to write text blocks, but I want to know if this is possible, just out of curiosity.
You cannot do this directly, you need to use a register, expression, or macro:
qq5aa<Esc>a<CR><Esc>q4#q
qq - record macro
5aa<Esc> - insert 5 a's
a<CR><Esc> - insert line break
q4#q - stop recording, repeat 4 more times
I do not normally like one-liners, but this seems to work:
:for i in range(5) | for j in range(5) | execute 'normal ia' | endfor | execute "normal A\<CR>" | endfor
and this is a lot shorter:
:for i in range(5) | execute 'normal 5aa' | put='' | endfor
<esc> i a <esc> x 5p dd 5P
esc - switch to normal mode
i - switch to insert mode
a - print "a"
esc - switch to normal mode
x - deleta "a"
5p - paste a 5 times ("aaaaa")
dd - delete line "aaaaa"
5P - paste line "aaaaa" 5 times
:norm 5oaaaaa
is the simplest way I could think of to obtain a 5x5 matrix of a's but I don't think it satisfies your curiosity.
One could also do:
:norm Oaaaaa
5#:
but that's not really recursive either.
So… I don't know!

how to tail the penult occurence of a pattern in a file

I know that using tail -1 I can take the last of occurence of a specific pattern in a file. But how to tail the penult? I tried tail-2 which gave me the penult and the last.
I am using bash
thanks
You can chain head/tail:
tail -3|head -2
which, assuming you've got a file like this:
a
b
c
d
e
will have tail produce
c
d
e
and then head grabs
c
d
sed -n 'x;$p' inputfile
This swaps the current line into hold space and the previous line into pattern space. On the last line, the contents of pattern space is printed (which happens to be the penultimate line.

Resources