4

I have a long list of different names of universities. I'm trying to build a synonym table by collating lines with certain unique keywords; that is, in the file, I'll identify that Harvard is the keyword here:

Harvard Business School|
Harvard College|
Harvard School of Divinity|

and paste them into another file as

Harvard Business School|Harvard College|Harvard School of Divinity|

I have been doing this by searching for the word under the cursor, yanking lines with that word into register, pasting the register into the other file, and using the join command "J" to join the lines together:

[ clear register 'a' ]    
0"ay0
[ move cursor to 'Harvard" and yank lines with keyword into register a ]
:g/\<<CTRL-R><CTRL-W>\>/y A
[ move to other screen and paste ]
"ap
[ join lines ]
JJJJJ

This works just fine, but I'd like it to be streamlined. Specifically, I would like to know how to remove newlines from a register so that I don't have to use JJJJ to manually join the lines in the last step. I'd like to search for all lines containing the word under the cursor, copy them into the 'a' register, remove newlines from the 'a' register, then paste the contents of the 'a' register.

Any ideas?

EDIT: I know:

  • how to search and replace globally, e.g. %s/\n//g
  • how to search and replace 'foo' in a buffer from a word to the contents of a register, e.g. :%s/foo/a/g
  • how to search for the contents of a register and replace with 'foo' in a buffer, e.g. :%s/a/bar/g

What I need to know:

  • how to search and replace 'foo' with 'bar' from register 'a' to register 'b'
  • how to search and replace 'foo' with 'bar' from register 'a' to register 'a'
Mike Bailey
  • 11,600
  • 12
  • 60
  • 118
Myer
  • 3,434
  • 1
  • 34
  • 46
  • does this have to be done in vim? Rather if you have a delimited list this could easily be accomplished in awk, python, sed, perl, et al. Rather, is this list standard, such that one school, one pipe and one '\n' per line? or is there other information contained on each line? – matchew Jun 03 '11 at 14:09
  • It's just the school and the pipe on the line. My question is actually about vim and not about how to solve the problem using other tools; I only provided the problem for context (and to see if there were any other vim solutions). – Myer Jun 03 '11 at 14:17
  • Fair enough, I've supplied my solution below. – matchew Jun 03 '11 at 14:19

4 Answers4

5

To do it directly with text in register a you could use this command:

:let @a=substitute(strtrans(@a),'\^@',' ','g')

Then you should get results you want when you paste register a back in.

Herbert Sitz
  • 20,640
  • 8
  • 45
  • 51
  • Can you explain what's going on here? I understand the let @a=substitute(strtrans(@s) part, just not the middle two parameters of substitute() – Myer Jun 03 '11 at 14:36
  • This almost does it, but it adds superfluous ^@ to the beginning of every appended line: ^@Adelphi University|^@Adelphi College| - I'm unsure what \^@ means or how to look it up on google or in vimhelp. – Myer Jun 03 '11 at 15:08
  • @Peter -- Here's how I think it goes: Multiline text in a register doesn't have ^M chars, instead each line is terminated by the null char, '^@'. To substitute a space for that char you first need to use strtrans() to convert it into the two character literal, `^@`. The backslash in front of `^@` is so `^` is not read as 'begin of line' special char. So what's happening is (1) null chars get converted to two char `^@`, then each occurrence of two char sequence gets substituted with space char. Not sure why final arg doesn't have to be global flag (`'g'`) but it seems to work either way. – Herbert Sitz Jun 03 '11 at 15:13
  • Thanks for the explanation. Any idea why the ^@ results are showing up in the output - any way of getting rid of them? I've read http://stackoverflow.com/questions/71323/how-to-replace-a-character-for-a-newline-in-vim and http://stackoverflow.com/questions/71323/how-to-replace-a-character-for-a-newline-in-vim and it is still not clear what I have to do to get this to work. – Myer Jun 03 '11 at 15:17
  • @Peter -- No, the ^@'s shouldn't be showing. They were because you do indeed need to set the 'g' flag as last arg of substitute. I changed my answer to reflect that. – Herbert Sitz Jun 03 '11 at 15:18
  • @Herbert Sitz. There are no NULL characters possible in the string, only NLs. NULL characters from the buffer are replaced with NLs in the registers: you can test this by running `call append('.', ["-\n-"]) | .+1yank a | echom strtrans(@a)`: you will get `-^@-^@` where first `^@` is a NULL as shown in buffer and second is line end. Why do you run substitute on transformed string and not `substitute(@a, "\n", ' ', 'g')`? – ZyX Jun 04 '11 at 08:33
2

You don't need to remove newlines from register or press more then one J: with the following mapping it will be "apgVJ:

nnoremap <expr> gV    "`[".getregtype(v:register)[0]."`]"

This mapping makes you able to select pasted text just after it was pasted. J on selected region joins all lines in region (unless region has only one line: here J acts like J without a selection, joining current line with next). gV tip can also be used to do substitution: "apgV:s/{pattern}/{replacement}<CR> is more convenient then using "ap:let @a=substitute(@a, '{pattern}', '{replacement}', '{flags}') unless you define some smart mapping.

Another tip is that register a can be cleared using qaq normal mode sequence: qa starts recording a new macro and q immediately stops it leaving empty string in a register where macro is recorded to.

ZyX
  • 49,123
  • 7
  • 101
  • 128
1

Late to the game, but since everybody else seem to have solved the wrong problem and since Google provided a solution for the problem that I had, I feel obliged to provide my solution.

Accumulate pattern matches as one line in "a

    :g/pattern/ norm "apkJ"addu

or using the unnamed register

    :g/pattern/ norm pkJddu

It doesn't remove newlines in the register, since it doesn't have to.

If you remove the u at the end of the norm-code, it will consume already used lines in the file, that would perhaps make the manual processing of the file easier, since you don't have to read stuff that has already been taken care of.

Cite:

   [ join lines ]
   JJJJJ

A question, why not use 5J, or visual mode, or :%j (joins all lines in a file)?

Off topic:

    "How do you mark text between "" in code blocks,
    not to be colour coded?"
mja
  • 262
  • 3
  • 8
0

If I can assume your text file looks like the following:

Harvard Business School|
Harvard College|
Harvard School of Divinity|

I would use

:%s/\n//g

to globally search and replace all \n new lines. sometimes, you may need to use ^M (hit control+v and ENTER) in place of \n.

I'm afraid your list may be more complicated then this, however, in which case my solution will be much too 'simple'

matchew
  • 17,544
  • 4
  • 40
  • 44
  • I'm afraid this doesn't work, because the newlines transmit information in both files. In the copyto file, I don't want all the universities on one line, I want only universities that are actually the same on one line - that's whole point of the problem (search and replace *in registers*) . – Myer Jun 03 '11 at 14:30
  • Oh, I see. I understand now. Hold On, I'll be back with another answer. It may take a few minutes...seeing how I am at work – matchew Jun 03 '11 at 14:36