Select first word from each line in multiple lines with Vim - vim

I would like to copy the first words of multiple lines.
Example of code :
apiKey := fmt.Sprintf("&apiKey=%s", args.ApiKey)
maxCount := fmt.Sprintf("&maxCount=%d", args.MaxCount)
id := fmt.Sprintf("&id=%s", args.Id)
userid := fmt.Sprintf("&userid=%s", args.Userid)
requestFields := fmt.Sprintf("&requestFields=%s", args.RequestFields)
I would like to have this in my clipboard :
apiKey
maxCount
id
userid
requestFields
I tried with ctrl-v and after e, but it copies like on the image :

You could append every first word to an empty register (let's say q) using
:'<,'>norm! "Qyiw
That is, in every line of the visual selection, execute the "Qyiw sequence of normal commands to append (the first) "inner word" to the q register.
You need to have > in cpoptions for the newline to be added in between yanks (:set cpoptions+=>), otherwise the words will be concatenated on a single line.
If you want to quickly empty a register you can use qqq in normal mode (or qaq to empty register a).
Note: the unnamed register ("") will also contain what you want at the end of the operation, so you don't need to "qp to paste it, p will do.

I think the chosen answer is a really good one, the idea of appending matches to registers can be pretty useful in other scenarios as well.
That said, an alternative way to get this done might be to align the right-hand side first, do the copying and then undo the alignment. You can use a tool like tabular, Align or easy-align.
With tabular, marking the area and executing :Tab/: would result in this:
apiKey : = fmt.Sprintf("&apiKey=%s", args.ApiKey)
maxCount : = fmt.Sprintf("&maxCount=%d", args.MaxCount)
id : = fmt.Sprintf("&id=%s", args.Id)
userid : = fmt.Sprintf("&userid=%s", args.Userid)
requestFields : = fmt.Sprintf("&requestFields=%s", args.RequestFields)
You can now use visual block mode to select the first part, and then use u to undo the alignment.

Relying on the external cut program:
:'<,'>!cut -d' ' -f1

Related

how do I get rid of leading/trailing spaces in SAS search terms?

I have had to look up hundreds (if not thousands) of free-text answers on google, making notes in Excel along the way and inserting SAS-code around the answers as a last step.
The output looks like this:
This output contains an unnecessary number of blank spaces, which seems to confuse SAS's search to the point where the observations can't be properly located.
It works if I manually erase superflous spaces, but that will probably take hours. Is there an automated fix for this, either in SAS or in excel?
I tried using the STRIP-function, to no avail:
else if R_res_ort_txt=strip(" arild ") and R_kom_lan=strip(" skåne ") then R_kommun=strip(" Höganäs " );
If you want to generate a string like:
if R_res_ort_txt="arild" and R_kom_lan="skåne" then R_kommun="Höganäs";
from three variables, let's call them A B C, then just use code like:
string=catx(' ','if R_res_ort_txt=',quote(trim(A))
,'and R_kom_lan=',quote(trim(B))
,'then R_kommun=',quote(trim(C)),';') ;
Or if you are just writing that string to a file just use this PUT statement syntax.
put 'if R_res_ort_txt=' A :$quote. 'and R_kom_lan=' B :$quote.
'then R_kommun=' C :$quote. ';' ;
A saner solution would be to continue using the free-text answers as data and perform your matching criteria for transformations with a left join.
proc import out=answers datafile='my-free-text-answers.xlsx';
data have;
attrib R_res_ort_txt R_kom_lan length=$100;
input R_res_ort_txt ...;
datalines4;
... whatever all those transforms will be performed on...
;;;;
proc sql;
create table want as
select
have.* ,
answers.R_kommun_answer as R_kommun
from
have
left join
answers
on
have.R_res_ort_txt = answers.res_ort_answer
& have.R_kom_lan = abswers.kom_lan_answer
;
I solved this by adding quotes in excel using the flash fill function:
https://www.youtube.com/watch?v=nE65QeDoepc

Substituting everything from = to end of the line in VIM

Let's say I have several lines like:
$repeat_on = $_REQUEST['repeat_on'];
$opt_days = $_REQUEST['opt_day'];
$opt_days = explode(",", $opt_days);
... and so on.
Let's say I use visual mode to select all the lines: how can I replace everything from = to the end of the line so it looks like:
$repeat_on = NULL;
$opt_days = NULL;
$opt_days = NULL;
With the block selected, use this substitute:
s/=.*$/= NULL;
The substitution regex changes each line by replacing anything between = and the end of the line, including the =, with = NULL;.
The first part of the command is the regex matching what is to be replaced: =.*$.
The = is taken literally.
The dot . means any character.
So .* means: 0 or more of any character.
This is terminated by $ for end of line, but this actually isn't necessary here: try it also without the $.
So the regex will match the region after the first = in each line, and replace that region with the replacement, which is = NULL;. We need to include the = in the replacement to add it back, since it's part of the match to be replaced.
When you have a block selected, and you hit : to enter a command, the command line will be automatically prefixed with a range for the visual selection that looks like this:
:'<,'>
Continue typing the command above, and your command-line will be:
:'<,'>s/=.*$/= NULL;
Which will apply the replacement to the selected visual block.
If you'll need to have multiple replacements on a single line, you'll need to add the g flag:
:'<,'>s/=.*$/= NULL;/g
Some alternatives:
Visual Block (fast)
On the first line/character do... Wl<C-v>jjCNULL;<Esc>bi<Space><Esc>
Macro (faster)
On the first line/character do... qqWllCNULL;<esc>+q2#q
:norm (fastest)
On the first line do... 3:no<S-tab> WllCNULL;<Enter>
Or if you've visually selected the lines leave the 3 off the beginning.

How do I use a map in combination with search matches?

How do I use a map on every match found after a search?
I have created various functions which I invoke using a map.
I would like to use the maps on every search matches found.
If I search for dates in my text, how would I apply a i/v/nmap on every search-match found?
something like this?
%s/search-pattern/=\normal mode map/g
%s/search-pattern/=\insert mode map/g
Is it possible also to combine maps?
Hope I made myself clear.
Vim is quite powerful, and I suspect insert mode/normal mode maps are not the most convenient approach here.
Some idioms that may get you started:
Edit: I've built on your earlier question (
How do I visual select a calculation backwards?
) and provided a demo, explained in
chat
1. Record a macro:
qqniMyText<Esc>q
This will insert 'MyText' at each match position. Now, repeat a hundred times: 100#q
(consider setting :se nowrapscan to avoid restarting from the top).
2. Use :global
:g/somepattern/norm! Aappended<Esc>
will append the text 'appended' to each line containing the search pattern
3. Use smart substitutions:
You can do some 'static' edit actions using replacement patterns:
:%s/\v(\d\d)-(\d\d)-(\d{4})/\3\2\1/g
To transform dd-mm-yyyy into yyyymmdd date stamps.
To do a dynamically evaluated substitution (using vimscript with \= in the replacement expression) you can do virtually anything (including, sending mail or printing a document, if you would really want to):
:%s/\v<DB_\w+>/\=substitute(submatch(0), '\v_?([^_])([^_]*)', '\U\1\L\2', 'g')/g
To transform 'database style' names like
var DB_USER_ID = f();
var DB_USER_FIRST_NAME = f();
var DB_USER_LAST_NAME = f();
var DB_USER_HOME_ADDRESS = f();
into 'camel case style names' like:
var DbUserId = f();
var DbUserFirstName = f();
var DbUserLastName = f();
var DbUserHomeAddress = f();
Live demo with expression evaluations
Edit In response to the comment/chat: You can use the approach #1 for this quite easily:
/\v\c\s*\zs(\s{-}(((sqrt|log|sin|cos|tan|exp)?\(.{-}\))|(-?[0-9,.]+(e-?[0-9]+)?)|([-+*/%^]+)))+(\s*\=?)?\s*
qqa<M-.><Esc>nq
Now you can repeat for all of the document:
:set nowrapscan
100#q
If there's only one match in every line, you could use :global instead of :s:
:%g/search-pattern/normal nrX
The :[range]normal positions the cursor at the beginning of the line, therefore the n to go to the first match before the mapping (I use rX as an example). You could write a custom command that would handle all matches in a line, but I would solve your use case with a recursive macro instead:
First, perform the search: /search-pattern, then record a macro containing your mapping, which jumps to the next match at the end: qarXnq. You can now manually apply the macro repeatedly via #a, or make it recursive via qA#aq, or :let #a .= '#a'. Execute this once #a, and it will run until it runs out of matches.

Add a number of '=' in a rest (reStructuredText) document that equals to characters from last line?

I want to use a shortcut to add needed = (from Section/Title reStructuredText syntax) according to the last line.
So, suppose (being | the cursor position)
Title
|
and pressing an specific mapping mapped to a function, add a number of = that equals to the last line (where Title is), becoming:
Title
=====|
This sequence will get you close:
kyyp:.s/./=/g
Duplicate the previous line, then in that line, change every character to an equals sign. Map that to a key sequence you like, and try it out.
Another way:
:execute "normal " . strlen(getline(line(".") - 1)) . "i="
strlen(getline(line(".") - 1)) returns the lenght of the line above the current position. The result is that the command Ni= is executed, inserting = N times.
For a mapping I would have used:
put=repeat('=', col('$')-1)
For something more interactive, I would have use the same solution as Ned's.
(I don't like my mappings to change the various registers like #" or #/)
My vim-rst-sections vim plugin will convert lines to section headings:
http://www.vim.org/scripts/script.php?script_id=4486
In your case, you'd put the cursor on the line, and type <leader><leader>d to get a top-level heading like this:
#####
Title
#####
A few repeats of <leader><leader>d will take you down to the standard hierarchy of Python ReST sections to the =.

Copy matching text to register

does anyone know if it is possible to concatenate matches resulting from a search into a single register? E.g, I have a file with following contents:
aaa :xxx 123
bb :y 8
ccccc :zzzzz 1923
Now what I want is to copy column starting with ':' somewhere else. Unfortunatelly I can't use visual block mode, because the first column hasn't fixed width.
I thought that I could search for the second column (:\w+) and store the maches into a register.
Another way:
:g/:/norm f:"Aye
Per :h quote_alpha, if you use an uppercase register name, it appends rather than replaces the contents of the register. If you run this and check the contents of register "a, you'll see
:xxx:y:zzzzz
(Possibly with linebreaks, depending on how you have cpoptions set.)
You could make a macro:
qa (make a macro and store it in register a).
"Rye (yank to end of word and append it to register r - capital means append, lowercase overwrite.)
n (next match)
q (end recording)
If there are 10 matches, do 10#a
Make sure register r is empty when you begin.
Add this to your .vimrc or create any file in the vim plugin folder with the following content.
After you execute this lines through .vimrc or plugin, use :CopyTextAfterColon command and then simply insert from the system buffer text you need.
function! s:copy_after_colon()
let values = ''
let pattern = '^.*:\(\w\+\).*$'
for line_number in range(1, line('$'))
let line = getline(line_number)
if line =~ pattern
let value = substitute(line, pattern, '\1', '')
let values .= value."\n"
endif
endfor
let #* = values
endfunction
command! -nargs=0 CopyTextAfterColon call <SID>copy_after_colon()
You can adapt this later for different purposes.
I would first start with parsing the file. For this use TextFieldReader rather than inventing your own CSV parser:
using Microsoft.VisualBasic.FileIO;
TextFieldParser reader = new TextFieldReader("C:\MyFile.txt");
reader.Delimiters = new string[] { " " };
string[] currentRow = null;
while (!reader.EndOfData)
{
try
{
currentRow = reader.ReadFields();
foreach(string field in currentRow)
{
//save this field...
}
}
catch (MalformedLineException ex)
{
//handle exception the way you want
}
}
Once I have the data I would extract just the column that I am interested in. If you can assume that each line has the same pattern then you can figure out the right column during parsing the first row and then while parsing the rest of the rows you can just save the appropriate column. You don't have to save the whole file into the memory.
EDIT: I am terribly sorry, I thought the question was about C# programming. My mistake - sorry.

Resources