Why vim's d operator is misbehaving? - linux

Few days ago I decided to use the Vim text editor... playing around with the vimtutor I found something very rare with the d operator; Vim session:
Case 1
before: The Quick Red Fox Jumps Over the Lazy Brown Dog
after :    The Quick Red F Jumps Over the Lazy Brown Dog
results: as expected.
Case 2
Placing the cursor in the last character of a word.
before: The Quick Red Fox Jumps Over the Lazy Brown Dog
after :    The Quick Red Fo Over the Lazy Brown Dog
results: de deletes the "x Jumps" substring.
Case 3
Placing the cursor in the last character of the last word.
before: The Quick Red Fox Jumps Over the Lazy Brown Dog
after :    The Quick Red Fox Jumps Over the Lazy Brown Do
results: as expected.
Please note that:
In both cases I'm using the de command.
after: reflects the changes after applying the de command.
The highlighted part represent the cursor position in the editor.
Questions:
Is this a bug?
Am I doing something wrong?
What is happening?
Vim version: version 7.3.50; Modified by Gentoo-7.3.50

When you are already at the end of word, de will delete to the end of next word.
d is a operator command. It accepts a motion command(e or others).
When you press e at the end of word, you can see that behavior is consistent.

When pressing e, vim takes you to the end of the word. If the cursor is on the x in fox, you are already there, so e takes to the next end of a word.
Thus, de will delete jumps as well.

Keep in mind that de is 2 commands d deletes. e is end of word.
Issuing e at the end of one word jumps to the end of the next word. So de deletes from the current position to the end of the next word. You might want to try dw or daw
See also :help e and :help d

Related

Find identical phrases in strings

I have sets of texts. The texts are rather short (up to 500 characters). The sets consist of up to 10 texts.
I try to find phrases as long as possible which occur in most of the texts. In other words I am looking for identical substrings. The longer the better and the more texts they occur in also the better.
Example:
"The red brown fox jumps over the lazy dog"
"The red haired girl smokes brown cigars"
"Where the yellow fox jumps over the haywire"
"All the boys like a red brown fox"
"A girl like a fox jumps over the dead boys grave"
Phrases (one word phrases ommitted):
"red brown fox", length 12, occurence 2
"fox jumps over the", length 18, occurrence 3
"The red", length 7, occurrence 2
Phrases like "brown fox" or "fox jumps" are omitted, because they are subphrases of longer phrases.
I am looking for an algorithm to find those phrases.
Finding the longuest commun substring is a commun DP algorithm explained pretty well here. https://www.geeksforgeeks.org/longest-common-substring-dp-29/ .
After to find the occurence of the strings in the set of text you can simply use a code loke this.
substring = "red brown fox"
n = 0
for text in texts:
if substring in text:
n = n + 1
print(substring, n)
As every substring is a prefix of some suffix, traversing a generalised suffix tree ought to let us compare paths both by how many leaves from different texts they share, indicating quantity of texts sharing a substring, as well as how long the distances to the leaves, indicating shared substring lengths.

How to move/shift around several rows in V-line mode using vim. Lines are 2 rows apart

For example, I want to select lines starting with B28, B29 and B30 using Shift + v in row B28 , then select row B29 and so on..., then press 'd' and then move to ROW 1 and press 'Shift-p' in the first row to paste all these rows there.
ROW 1
A26 51.00824
D26 35.94841
D27 35.94841
B28 7.07486
A28 35.95497
D28 179.99932
B29 4.15400
A29 90.00068
D29 179.99932
B30 7.07490
Visual mode(s) can only select contiguous regions (this applies to characterwise, linewise, and blockwise visual mode, regardless of the value of virtualedit). The only exception is ragged line-endings with, say, vip$.
But you can accomplish your goal other ways. For example:
:global/^B\d+/move /ROW 1/-
Should move all lines starting with B followed by digits to the line after ROW 1. (They will probably be reversed; in your case, a simple :sort n will probably be do, but generally :[range]!tac or :[range]global/./move <firstline> can reverse lines.)
Or, you could record a macro like so:
Mark insertion point: :/ROW 1/mark a
start a recursive macro in register q: qqqq (the first three clear the register)
go to next occurence to move /^B\d+
move it dd'ap
adjust mark ma
recursive invocation #q
fini q
Now hit #q and watch the magic.
If you needed to repeat the above many times for different things, I would write a series of commands to get it working once, then turn that into a function and generalize the things that are variable. Voilà, automation.
Another method, just for fun:
:g/^B/normal! dd1G}P
:g/^B/<cmd> executes <cmd> on every line starting with a B,
normal! <macro> executes normal mode macro <macro>,
dd cuts the line to the unnamed register,
1G moves the cursor to line 1,
} moves the cursor to the empty line after the current paragraph, this is key because it allows us to put the next line below the last one that was put and thus to respect order,
P puts the content of the unnamed register above the current line.
Reference:
:help :global
:help :normal
:help /^
:help dd
:help G
:help }
:help P
--- EDIT ---
There are plenty of ways to address your target, even if it is not on line 1.
With a line number:
:g/^B/normal! dd23G}P
With a mark:
ma
:g/^B/normal! dd'a}P
With a search:
:g/^B/normal! dd?ROW1^M}P " ^M is obtained with <C-v><CR>

How to select all LINES between parenthesises in VIM

Say I have the following code
aaa;
bbb;
ccc void () {
xxx;
yyy;
}
ddd;
eee;
Now suppose my cursor is at yyy. I'd like to highlight all code between the parenthesis { and } inclusive of the complete line the brackets are on. This means the highlight will look like
before select
after select
va} is not a solution as that produces this
Effectively it should be a linewise selection. But the corresponding "text-object" forces a charwise one (so there's no difference between va{ and Va{).
However, you can make a selection linewise anytime. So va{V achieves the desired result.
I'm not sure if any mapping is needed at all. But at least ab should not be touched as it normally stands for parentheses ("()-block").
vnoremap aB aBV
Now vaB will select {}-block linewise, while va{ will do "normal" {}-block selection.
nmap vab va{$o0
Breaking it down
vab
highlights within the brackets inclusive of the brackets. The cursor finishes at the end of the highlight.
$
moves the cursor to the end of the line
o
moves the cursor to the other end of the highlight block
0
moves the cursor to the start of the line

Vim expand selection by a paragraph

If I have a visual selection in vim, how do I expand the selection to include the next paragraph? Also can I press o and do the same to select the previous paragraph?
You can use the ap or ip text-objects for "a paragraph" or "inner paragraph". A paragraph is a block of text separeated by blank lines. ap also includes the blank lines after the current paragraph. There is also { and } motions to move amongst paragraphs.
So to get the next paragraph you can do 2} or }ap.
For the previous paragraph, indeed, use o to go to the other end of your selection and 2{.
You can also add a count to ap, e.g 2ap will select the current and the next paragraph.

How to count a keyword in a series of text strings within multiple cells in Excel?

I've found similar ideas on here by using SEARCH or FIND in Excel, but those seem to be more about finding the location of the keyword, rather than counting how many times it comes up.
I have a CSV of a shot list. Each shot is associated with a sequence, and each shot has a set of "tags" (this is the text string). Please see below for an example:
There are two main keywords I'd like to keep track of: "dog" and "fox". There are multiple shots per sequence, and my goal is to figure out how many shots per sequence have the "dog" tag and how many have the "fox" tag. The formula I need would be for the columns highlighted yellow, and I have manually entered the first few entires to give an idea of what number should be there. Once those are filled in, I can then count the ratio per sequence of which ones are tagged more for "dog" or "fox".
I can't use text-to-columns in Excel to easily break down the text string column, because each one contains a different series of tags (somewhat demonstrated by my sample text).
I've figured out a simple formula to count what I want if the text column only had "dog" or "fox" in it, but I can't figure out how to get Excel to find one word within a text string and count it.
=SUMIFS(D:D,B:B,1,F:F,"dog")
1 being the sequence number, and the rest of the columns are referencing my larger data sheet.
Any help would be much appreciated!!
Edit:
Sheet in text form here (sorry about formatting, cant upload a file from work ATM):
COUNTER SAMPLE DATA
Sequence Total Fox Total Dog Total Entries Ratio Fox Ratio Dog Sequence Shot Text
1 2 2 4 0.5 0.5 1 mov_101 The quick brown fox
2 3 2 5 0.6 0.4 2 mov_102 jumps over the lazy dog
3 4 3 mov_103 The fox and the hound
4 2 4 mov_104 fox news
5 3 5 mov_105 I am a dog
1 mov_106 The fox and the hound
2 mov_107 jumps over the lazy dog
3 mov_108 The fox and the hound
4 mov_109 jumps over the lazy dog
5 mov_110 I am a dog
1 mov_111 jumps over the lazy dog
3 mov_112 The fox and the hound
5 mov_113 The fox and the hound
2 mov_114 jumps over the lazy dog
2 mov_115 fox news
1 mov_116 I am a dog
3 mov_117 I am a dog
2 mov_118 The fox and the hound
You were close, you need to use COUNTIFS instead of SUMIFS to get the count of sequences. And use "*" around word fox and dog to consider surrounding words.
Here is the formula that I've used to get fox count:
=COUNTIFS($H:$H,$A2,$J:$J,"*fox*")
Place this formula in cell B2 and drag it down.
Same way, following formula will get you the dog count per sequence:
=COUNTIFS($H:$H,$A2,$J:$J,"*dog*")
Place this formula in cell C2 and drag it down.
So I tried to replicate your data and this is what I've used:
Let me know if you have any doubts.
Someone will probably have a better solution than this, but I've used it before when looking for a similar function and couldn't find one.
=(LEN([textcell]) - LEN(SUBSTITUTE([textcell], [wordcell], ""))) / LEN([wordcell])
What this does is compare the length of the original string, with the length of the string with the search word removed. Dividing it by the length of the word, giving you how many occurrences were removed.
So given the following content :
fox dog search
1 0 The quick brown fox
0 1 jumps over the lazy dog
The formula on A2 is
=(LEN($C2) - LEN(SUBSTITUTE($C2,A$1, ""))) / LEN(A$1)
Dollar signs not required, but made it so I could copy the formula to all 4 cells.
If your Sequence column is E, and the column with text is F, you could use this formula:
=SUMPRODUCT(--(NOT(ISERROR(SEARCH(B$1,$F$2:$F$6)))),--($E$2:$E$6=$A2))
This creates two arrays, one that's a sequence of 1's and 0's where 1 is that the text contains B1 ("fox" or "dog"), and another that is 1 for sequence matching and 0 for not sequence matching.
Then it multiplies and sums the arrays so you only get the count of when both conditions match.
The formula is in cells B2:C3 in my example:
Picture of sample data I used:

Resources