Add increment column in VisiData - visidata

In VisiData 1.5.2, how can I add a new column which contains the row number?
This can be done in version 2.0 by pressing i I think, but that does not work in 1.5.2. When I try that it says:
no command for "i"
Maybe there's a way of referencing the current row number in a expression?

This is more complicated than i, but it will work!
Use za to create a new column. Then move your cursor to that column, and press gs, then gz=. Type in range(n) where n is the number of rows in your sheet (you can reference the number in the buttom right corner).
Another option is that you can try putting the code for i (https://github.com/saulpw/visidata/blob/e2bbb7f60e069297f5da86f1cbe6faf3f606f72e/visidata/incr.py) in your installation of VisiData, and see if it 'just' works. VisiData's code was intentionally made very modular to allow for easier plug and play possibilities. Just make sure to add it to your imports in the __init__ file as well: https://github.com/saulpw/visidata/blob/2cb5379f413dc9d7f0baae3e4f351bb7268efb32/visidata/__init__.py#L101

Related

Fixed width flat file column addition via Excel or Notepad++

I have a fixed width flat file with n columns. I need to add a new column at the end that is a concatenation of some of the columns.
Eg.
0624 11011 LOCA
0624 11031 LOCC
0624 11041 LOCB
turns into
0624 11011 LOCA 0624LOCA-ABC
0624 11031 LOCC 0624LOCC-ABC
0624 11041 LOCB 0624LOCB-ABC
I imported file files as text in Excel and was able to generate the column quickly using the concatenate function.
But I now need to generate it as the flat file again. How do I do this?
Is there a feature in Excel to allow me to generate the sheet as a flat file with spaces. Or can I "transfer" the column to the same file in Notepad++.
I am looking for a handy keyboard option, else I have to go to SQL.
With Npp, I'd do:
Ctrl+H
Find what: ((\S+)\s+\S+\s+(\S+))
Repace with: $1 $2$3-ABC
Replace all
Make sure you have checked Regular Expression.
I assume that the delimiter is one space.
In Excel, click Save as, and choose the "save as type:" "Formatted Text (space delimited)".
Alternative, in Notepad++, if they are fixed width to start with, use Column Copy/Paste to build the extra column. (Hold Left ALT down while highlighting 1 column, CTRL+C then put cursor at end of first line, add a few spaces, click CTRL+V. Repeat for 2nd column ;)
If you need to add additional text to all columns (ie hyphen seperating them), Use the Left ALT trick again to highlight a zero width selection across all rows, then just type .. it'll mirror the typing for all rows :)
If you're file is significantly larger, however, I'd stick with Excel, or try Toto's Regular Expression replace ;)

How can I make a custom fill handle pattern?

I have a column A3:A71 I wish to populate with values
=COUNTIF(B3:B71,B3)
Where the second argument is incremented with every cell.
Obviously I don't want to copy this function every time, so I was hoping that fill handle would help me. However although it correctly increments the second argument of COUNTIF, it also increments the first one. Even if I correctly populate the first two or three cells in the column A3:A71 with the values
=COUNTIF(B3:B71,B3)
=COUNTIF(B3:B71,B4)
=COUNTIF(B3:B71,B5)
when I drag down from the bottom right corner, I get the function:
=COUNTIF(B6:B74,B6)
=COUNTIF(B6:B74,B7)
=COUNTIF(B6:B74,B8)
=COUNTIF(B9:B77,B9)
=COUNTIF(B9:B77,B10)
=COUNTIF(B9:B77,B11)
Can anybody please tell me how can I force the first argument to stay the same while the second one is increased correctly?
I am using MS Office 2011 for MacOS, but a Windows solution would be just as helpful.
Please try:
=COUNTIF(B$3:B$71,B3)
There are further details at OwenBloggers.com including a table:
and mention that other terms are “absolute cell reference” and “locking”.

VIM to delete a range of lines into a register

I am trying to delete a range of lines into a register a. Is this the easiest way to achieve this?
:5,10d a
The definition of "easiest" depends on what do you have, and what do you want to do
if you have a start line number and end number, e.g.
:2349,5344d a
is the easiest way.
You don't have to consider the questions like
"where is my cursor?"
"how many lines would be removed?"
...
If you are about to remove a small amount of lines, particularly they are on same screen. (You could use relative-linenumber.) for example: "a5dd but you have to move your cursor to the first line you want to delete. And this could be done by option 1 too: 5:d a<CR> (vim will automatically translate it into .,.+5d a<CR>)
If you just know the 1st line of deletion, and find the last line you want to delete by reading your text, (of course, small amount of lines) you could press V, and press j by reading, when it reaches the deletion ending border, press "ad
If the "range" in your question is the "range" concept in vim, The first option would be better. since it could be 234,540, it could be 1;/foo, /foo/,/bar/... :h range see detail
so back to the first sentence in my answer, There is no absolutely easiest way. It all depends on what do you have, and what do you want to do.
The other way to achieve this would be to highlight the range of lines in visual line mode. (Shift-V)
Then type "ad while in visual line mode. This will put the deleted lines into the a register.
" followed by a register puts the next delete, yank or put into that register.
Below is the documentation for " (quote)
*quote*
"{a-zA-Z0-9.%#:-"} Use register {a-zA-Z0-9.%#:-"} for next delete, yank
or put (use uppercase character to append with
delete and yank) ({.%#:} only work with put).
Another example of deleting multiple lines and putting it in a register. To delete 6 lines and put them in a register you can got to the line and type "a6dd. This puts the 6 deleted lines into register a.

Converting a number (non-currency) value to a text entry

Easy enough concept, but I have no idea where to start when it comes to creating a UDF, which is the only thing I can find any mention of. I have a column that populates on source sheets with either a 1 or 2. I want to do something so that all of the "1's" shows as one text entry("AA" for example) and all "2's" show as a different entry(say "BB"). Is this possible without a UDF; and if not then is there any advice on where to start?
You can use custom formatting for this. Right-click the column in question and choose "Format Cells." In the dialog, choose "Custom" and in the box at the top enter:
[=1]"AA";[=2]"BB";General
This assumes that the "1" or "2" is the sole content of the cell. Any other number or text will display in the General format.
This may help you as well. It is a conditional statement that will reference one cell the check if there is content, if not then it will put the word "None" in, otherwise it will put the contents of the cell.
=IF((Sheet1!J1089)="","None",Sheet1!J1089)
Just to update anyone else that may be interested. I have a solution that I am using. Had to go the vba route, but I've got it set up so that my macro for running reports runs the following:
Sub Conversion()
Dim X As Long, DBCodes() As String
DBCodes = Split("AA,BB,CC", ",")
For X = 1 To 3
Columns("H").Replace X, DBCodes(X - 1), xlWhole
Next
End Sub
I can change the split values and the line after for as many more values as I need replacing, though it would take fiddling with to find the point where too many values would make it impractical. Also, it makes a world of difference where I put in the line to run this; found the best spot though and even the reports that are 600+ rows the conversion only adds a couple seconds.

Align columns in VI

I have a bunch of lines that I'd like to split into two columns, and get the data from each column. The data looks something like this:
current_well.well_number
current_well.well_name
current_well.well_type_code
well_location.section
well_location.range
Essentially what I'd like to do is split the line based off of the period, turn the data into two columns, and then grab the data for each column. I know this can be done in Excel, but I'm really interested in VIs solution for this problem. I know that
%s/\./
will format the string with empty spaces. But once I have the data looking like:
current_well well_number
current_well well_name
current_well well_type_code
well_location section
well_location range
How do I grab all the values for each column so I can paste it into another application?
The linux column command works well for creating the columns
:%!column -s . -t
Then use block copy.
One option is to use this Align plugin to line up the periods so you can more easily select a column in Visual Block mode. e.g. if you do this:
:%Align \.
You'll end up with:
current_well . well_number
current_well . well_name
current_well . well_type_code
well_location . section
well_location . range
If you don't want to use a plugin, try padding your columns with spaces. e.g. for your text:
:%s/\v(.*)\.(.*)/\=printf("%-16s %s", submatch(1), submatch(2))/
That'll leave you with:
current_well well_number
current_well well_name
current_well well_type_code
well_location section
well_location range
Then you can Ctrl-V and select a column of text to copy. Just make sure you pick a column width wider than your widest value.
I've run into this problem a number of times. Changing the dots to tabs will line them up mostly nice, but not really. It's true that all the columns will start on a tabstop, but there's no guarantee that they'll be on the same tabstop. For instance, if this was your original text:
lt1tab.value1
gt1tabstop.value2
and you do:
%s/\./\t/g
and assuming a tabstop is 8 spaces, you'll get:
lt1tab value1
gt1tabstop value2
What you might want to do instead is remove everything but the last column (or whichever column you want). For instance:
%s/^.*\.//
will leave you with:
value1
value2
Which you can easily copy and paste.
If you don't have to use Vim, you can use unix's cut to do what you want:
cut -f2 -d. input_file > output_file
I do this all the time, simply by padding with a lot of space:
%s/./ /
Then <c-v> to enter block mode in the empty space, draw the column position I want, < to shift the text to the right toward my column, then hold down .. Takes seconds.
Another way you can do it if you know the specific column position you want to line up on: go to the first line and start recording (qq), find your delimeter (f.), insert a bunch of space (20i <esc>), delete space back to a specific column (d15|), then move down a line (j). Then you just hold down shift and roll your fingers across #Q a bunch of times (or use a count 10#q) until all the columns are lined up. :)
Obviously, the above methods with block select and/or Excel are easier. But I'm a masochist and I decided to assume you didn't have access to either of those and try to do it with only vi commands. Here's the horrible thing I thought up:
My basic plan is to turn the list of joined columns into two lists, one after the other. This basically involves breaking each row into two lines, then copying every other line to the end of the file.
So, first we have to break each line into two lines with this command:
:%s/\./^M/
Next, swing by the bottom of the file and create an empty line, then return to the first line. This will help with readability later.
Go[Esc]
:1
Now, you need to map the following sequence to your favorite key:
:map [Key] mkjddGp'kj
(For the record, this marks the current row, deletes the row below it, pastes that row at the bottom of the file, returns to the row you started from, and then moves to the next row.)
Finally, press the mapped key once for every row in your list. So, with the example list, you'd press it 5 times. Make sure you start from the first line in the list!!
What you'll have at the end is the following:
current_well
current_well
current_well
well_location
well_location
well_number
well_name
well_type_code
section
range
You can now easily copy each list to wherever you need to put them.
Ctrl V selects a column
Why not block visual mode ? C-v, select what you want, and paste it in some other application.
For that kind of pasting, you should probably set
:set guioptions+=a
as well.
Hmm, now that I've re-read your question. Are you asking how to divide the data into columns, or how to paste it in some other app ?
I think I got it now (3rd reading).
Do as you've done and get the spaces where the dots used to be. Then do another substitution, and replace the spaces with tabs, each tab being, 15 or something. It will line them up nicely.
Then you can select and copy them to wherever.
You can also match the regex to select the second column for example, but although it is light up like a christmas tree, you won't be able to yank it.
I'd convert the dots to tabs, then block select each column:
:%s/\./CtrlV-Tab/g
CtrlV to then block select the columns.
Or, as you'd have tab separated values, they will paste directly into columns in Excel.
At the top of the file:
!}awk -F. '{print $1}' >> %
You will be told the file has changed. Select the L (load) option.
Add a blank line under the original lines, go back to the top.
for(i=1;i<=NR;i++);print $2 >> %
Again select the L option
Delete the original lines.
You now have the first and second parts in two groups.
One possible solution:
w (or W for WORDS) jumps to next word,
CTRL-R CTRL-W gets the word under cursor and pastes it into command-line
Now you have to chain those commands in a loop and then output them in your own manner.
You can select columns in gvim by typing either Ctrl-VCtrl-G or Ctrl-QCtrl-G (depending on if you are using windows insert key mappings) and then selecting with the mouse.
nnoremap <BS> v"by:%!column -t -s<C-r>b -o' '<CR>
This is a nice solution following on from #NES & #SergioAraujo idea. Put it in your vimrc.
USAGE. Move the cursor to the delimiter. Then hit Backspace.
Explanation we use the named register b to hold our delimiter. Then substitute it as the variable for the --separator option of the column UNIX utility.
And Backspace is a good key because in normal mode is the same as h. But then again you might also be prone to hitting it accidentally.

Resources