Vim - swap columns with visual mode - vim

I have a markdown table like this.
I want to swap head3 column with head2.
| head1 | head3 | head2 |
|-------|-------|-------|
| foo | baa | none |
| some | text | here |
I can easily cut the column using visual mode (Ctrl-V), but how can I paste the column 'column-wisely'?
Also, which operating is easiert:
cut 'head 3' and paste behind 'head2'
cut 'head 2' and paste before 'head3'?

When you've selected and cut something with Ctrl+V, Vim will paste it as a column too. You can Ctrl+V select the column you want to swap into and paste, and the column you just replaced will now be in your paste register. Go back to the column you cut first and paste one more time to move the replaced column.
In steps:
Use Ctrl+V to select the entire head3 column
x to cut
Use Ctrl+V again to select the entire head2 column
p to paste
Move back to where head3 used to be
p to paste

Move to the first pip | : f+| then to the character right after it by l
Start selecting the column: Ctrl+v
Move to the end of the file: G
Move to the second pip, the one after the header3: 2f+|
Cut the selection: d
Move to the end of the line: $
And finally paste: p
Also, which operating is easiert:
cut 'head 3' and paste behind 'head2'
cut 'head 2' and paste before
'head3'?
For me, both work the same way.

Related

Substracting part of cell

So lets say that in one row i have in 2 cells some data and I want to extract the data after the second "_" character:
| | A | B |
|---|:----------:|:---------------------:|
| 1 | 75875_QUWR | LALAHF_FHJ_75378_WZ44 | <- Input
| 2 | 75875_QUWR | 75378_WZ44 | <- Expected output
I tried using =RIGHT() function but than i will remove text from this first cell and so on, how can i write this function? Maybe I would compare this old cell and than to do if the second row is empty because maybe function deleted it to copy the one from first? No idea
Try:
=MID("_"&A1,FIND("#",SUBSTITUTE("_"&A1,"_","#",LEN("_"&A1)-LEN(SUBSTITUTE("_"&A1,"_",""))-1))+1,100)
Regardless of the times a "_" is present in your string, it will end up with the last two "words" in your string. Source
Use following formula.
=TRIM(MID(A1,SEARCH("#",SUBSTITUTE(A1,"_","#",2))+1,100))

Multiple text insertion in Linux

Can someone help me how to write a piece of command that will insert some text in multiple places (given column and row) of a given file that already contains data. For example: old_data is a file that contains:
A
And I wish to get new_data that will contain:
A 1
I read something about awk and sed commands, but I don't believe to understand how to incorporate these, to get what I want.
I would like to add up, that this command I would like to use as a part of script
for b in ./*/ ; do (cd "$b" && command); done
If we imagine content of old_data as a matrix of elements {An*m} where n corresponds to number of row and m to number of column of this matrix, I wish to manipulate with matrix so that I could add new elements. A in old-data has coordinates (1,1). In new_data therefore, I wish to assign 1 to a matrix element that has coordinates (1,3).
If we compare content of old_data and new_data we see that (1,2) element corresponds to space (it is empty).
It's not at all clear to me what you are asking for, but I suspect you are saying that you would like a way to insert some given text in to a particular row and column. Perhaps:
$ cat input
A
B
C
D
$ row=2 column=2 text="This is some new data"
$ awk 'NR==row {$column = new_data " " $column}1' row=$row column=$column new_data="$text" input
A
B This is some new data
C
D
This bash & unix tools code works:
# make the input files.
echo {A..D} | tr ' ' '\n' > abc ; echo {1..4} | tr ' ' '\n' > 123
# print as per previous OP spec
head -1q abc 123 ; paste abc 123 123 | tail -n +2
Output:
A
1
B 2 2
C 3 3
D 4 4
Version #3, (using commas as more visible separators), as per newest OP spec:
# for the `sed` code change the `2` to whatever column needs deleting.
paste -d, abc 123 123 | sed 's/[^,]*//2'
Output:
A,,1
B,,2
C,,3
D,,4
The same, with tab delimiters (less visually obvious):
paste abc 123 123 | sed 's/[^\t]*//2'
A 1
B 2
C 3
D 4

Excel split data into columns

I have a column that each cell contains data of the following form:
COLUMN 1
a.jpg
b.jpg
c.jpg | d.jpg
fd.jpg | dsf.jpg | ksk.jpg
cccc.gif
das.png
___dhi.jpg | bdi.png
and so on..
I want the column to split at the character |
so that the cell c.jpg | d.jpg --> becomes
COLUMN 1 ---> COLUMN 1 COLUMN 2
c.jpg | d.jpg ---> c.jpg d.jpg
Excel's text to columns cannot process this as i want it as the characetr | is not present for cell that do not have more than one filename.
How can I split the column 1 to to corresponding columns and of cource keep the cells that contain one filename as they are?
TLDR : Use notepad.
Long version.. copy the column 1 content to notepad. Then select all > copy > Paste Special (in excel) > set delimiter as "|" . Finish.
Hope it helps. (:

how to replace the first column of a tab delimited file

690070 690070 A
690451 690451 B
690571 690571 C
690578 690578 D
690637 690637 F
How can I replace the first column values with a sequential number, starting from 1...n. So it becomes:
1 690070 A
2 690451 B
3 690571 C
4 690578 D
5 690637 F
Can this be done in Vim or some linux command?
You can use awk or vim macro.
awk is really great for such text manipulation
awk '{count++; print count " " $2 " "$3;}' data.stat > /tmp/data.stat && mv /tmp/data.stat data.stat
in Vim:
:let i=1 | g/^[^/\t]*\t/s//\= i. "\t"/ | let i=i+1
Reference
Update
For splitting the first two columns and saving into another file,
I recommend using awk as in Tomáš Šíma's answer, specifically:
awk '{print $1 "\t" $2;}' data.stat > newfilename.txt
If you want to to do everything in Vim:
Copy the current file to a new one
:w newfilename.txt
Open the newly copied file:
:o newfilename.txt
Split the first two columns of the rest of the line:
:%s/^\([^\t]*\)\t\([^\t]*\).*$/\1\t\2/g
Save your edits of course
:w newfilename.txt

Delete a specific Column in VIM/gvim with out using Visual Block mode

Sample Input File
+--------------------+---------+---------
| Name | S1 | S2
+--------------------+---------+---------
| A | -4.703 | -2.378
| B | -3283.2 | -3204.5
| C | 8779 | 7302
| D | 22078 | 18018
+--------------------+---------+---------
It is required to remove the S1 Column, i.e
Desired Output
+--------------------+---------
| Name | S2
+--------------------+---------
| A | -2.378
| B | -3205.5
| C | 7302
| D | 18018
+--------------------+---------
Can anyone help with this
thanks
Look, ma: no visual (block) mode !
My pragmatic approach wins would be: look for column anchors (-+-)
/-+-
Now, the column deletion is as simple as
d<C-v>N
(delete, block-wise, to the next occurrence of the column anchor from the end of the document).
Job done.
Fancy options
To account for multiple columns, you'd like to be precise about which column to match
This needs a little extra oomph
0f+
:exec '/\%' . col('.') . 'v\v[+|]'Enter
NC-vN
t+d
To see more about this \%22v way to select a virtual column, see
Support in vim for specific types of comments
In command mode:
:%s/^\([[+|][^+|]\+\)[+|][^+|]\+/\1/
This uses vim's built-in sed-like search and replace command. Here's the breakdown:
% - for the entire file
s - search for
/^ - the start of line
\([[+|][^+|]\+\) - followed by + or |, followed by any number (\+) of anything that is not + or |. This will get the first column, which we want to keep, so put it in a capture group by surrounding it with \( and \)
[+|][^+|]\+ - followed by + or |, followed by any number (\+) of anything that is not + or |. This will get the second column, which we don't want to keep, so no capture group.
/\1/ - replace everything we matched with the first capture group (which contains the first column). This effectively replaces the first and second column with the contents of the first column.
Like I said, vim's regex are pretty much identical to sed, so you if you look through this tutorial on sed you'll probably pick up a lot of useful stuff for vim as well.
Edit
In response to the OP's request to make this more generally capable of deleting any column:
:%s/^\(\([[+|][^+|]\+\)\{1\}\)[+|][^+|]\+/\1/
The index inside of the \{\}, now deletes the column indicated. Think of it like an array index (i.e. starts at zero). So \{0\} now deletes the first column, \{1\} deletes the second, and so on.
I would like to write Mathias Schwarz's comment into an answer because Visual Mode is the natural way for the task, although there is already an accepted answer.
Assuming cursor is in ¶
+--------------------+¶--------+---------
| Name | S1 | S2
+--------------------+---------+---------
| A | -4.703 | -2.378
| B | -3283.2 | -3204.5
| C | 8779 | 7302
| D | 22078 | 18018
+--------------------+---------+---------
Use normal command Ctrl-V8jf+d to select S1 column and delete it. Explanation:
Ctrl-V: Enter in Blockwise Visual Mode.
8j: Eigth is the number of rows of the table, it sets cursor at same column but last line.
f+: Move cursor until next + character.
d: delete visual selection.
And result is:
+--------------------+---------
| Name | S2
+--------------------+---------
| A | -2.378
| B | -3204.5
| C | 7302
| D | 18018
+--------------------+---------
If this is the only content of the file, the simplest way is to use this:
:%normal 22|d32|
IF there is more text in the file, specifies the line interval:
:X,Ynormal 22|d32|
Where X and Y is the line interval, for example: 10,17normal 22|d32|
If you're not familiar with the normal command and with the | "motion" there goes a quick explanation:
The normal command execute the following commands in the normal mode;
The | "motion" moves the cursor to a specified column, so 22| moves the cursor to the 22nd column;
Basically what :X,Ynormal 22|d32|does is to move the cursor to the 22nd column (22|) and deletes everything (d) until the 32nd column (32|) for every line specified by X and Y.
Based on patterns of your table, this can be achieved in two simple commands:
:%norm 2f+dF+
:%norm 2f|dF|
Where 2 is your column to remove (1 will remove 1st, 3 - 3rd).
This works as below (for each line at once):
Find second corresponding character of the column (2f+ or 2f|).
Delete backwards to the next found character of the column (dF+ or dF|).
Here is command line approach removing 2nd column in-place:
$ ex +'%norm 2f+dF+' +'%norm 2f|dF|' -scx cols2

Resources