开发者

Find every third value and insert cr or newline in VIM

So I have several large datasets that I need to make more readable and currently I'm having to go in and move to each 3rd value and insert a newline. I've tried several things in VIM to get this to work, but none seem to return the value that I'm looking for. Here's some of my data:

(0.96260310749184663, 4.3830008206495812, 0.84922658632317849),
(0.96260310749184663, 5.0000002088986637, 1.049701855818201),
(0.96260310749184697, 5.6169993576359696, 0.8492264385213405),
(0.96260310749184719, 5.9983257940402384, 0.32437568665165911),
(0.96260310749184719, 5.9983258053918069, -0.32437572732698844),
(0.96260310749184719, 5.6169994358349786, -0.84922691097323821),
(0.96260310749184697, 5.0000000093711492, -1.0497019267383632)

What I need to do is make it look like this instead:

(0.96260310749184663, 4.3830008206495812, 
 0.84922658632317849),
(0.96260310749184663, 5.0000002088986637, 
 1.049701855818201),
(0.96260310749184697, 5.6169993576359696, 
 0.8492264385213405),
(0.96260310749184719, 5.9983257940402384, 
 0.32437568665165911),
(0.96260310749184719, 5.9983258053918069, 
 -0.32437572732698844),
(0.96260310749184719, 5.6169994358349786, 
 -0.84922691097323821),
(0.96260310749184697, 5.0000000093711492, 
 -1.0497019267383632)

I used this on a selection to try and get it to move that 3rd value down, but it duplicated the entire thing and then moved the entire line down:

:'<,'>s/\([-[0-9.]\+,\s[-[0-9.]\+,\)/\1\r&/g

I also tried removing the 1 to make it work, but that didn't work either. So is there any way I can capture that 3rd value and insert a carriage return or newline to make this work? Thanks.

Edit---

I apologize for mis-communicating part of my problem: The data at the top is all on one line, not several lines. It looks like this:

(0.31852533878680489, 0.10352149350126813, -0.0046069731261429991), (0.31852526554320226, -0.103521543762028, -0.0046069731261429991), (0.19682845687859715,开发者_运维百科 -0.27102285045297636, -0.004606973126142444), (-8.1184530326649769e-05, -0.33500267513407755, -0.0046069731261416669), (-0.19699089317458821, -0.27102292369657782, -0.0046069731261408897), (-0.31868770183919259, -0.10352150714022559, -0.0046069731261403346), (-0.31868770183919221, 0.10352156674487166, -0.0046069731261403346), 


:g/./norm! 2Wi^M

Explanation:

  • :g/./{cmd} will run the {cmd} on every line
  • norm! will execute the following string as normal mode commands
  • 2Wi^M Move 2 WORDS then insert a return
  • ^M is accomplished by pressing <c-v><cr> or <c-q><cr>.

It is very tempting to do %norm! 2Wi^M, but this will fail as it messes up the lines that are being worked on.


Two approaches

1. ex commands and formatting

My first thought was textwidth:

:se tw=50
:g/./norm! gqq
:%s/^[^(]/ &/g

This

  1. sets text width to 50 chars
  2. reformats each (nonempty) line
  3. inserts a space at the start of any lines which don't start with (

2. use a macro

Alternatively: make a macro

gg
qq2f,a<CR><Esc>j0q
100000@q

Rationale:

  1. go to begin of buffer
  2. record macro q (qq starts recording, q ends recording)
    • 2f, - forward to second comma
    • a<CR><Esc> - append newline
    • j0 - next line, move caret to first character
  3. rinse and repeat (100000 is the number of times to repeat; processing will stop when the macro fails (e.g. at end of file)


Since the entire text to break is in one line initially, one can use a single short substitution command,

:s/,.\{-},\|), /&\r/g


The way I would do this would be something like this:

'<,'>s/^[^,]\+,[^,]\+,\zs/\r

Translated:

'<,'>     " Over the visual range
s/X/Y     " Substitute X with Y
^         " Start of line
[^,]\+    " Anything that isn't a comma, one or more, as many as possible
,         " A comma (end of first field)
[^,]\+    " Anything that isn't a comma, one or more again
,         " A comma (send of second field)
\zs       " Mark this point as the start of the match so we don't have to bother including all of the above in the result
\r        " We're replacing nothing at the end of the above match with a new-line (\r)

Another alternative:

'<,'>s/^\(.\{-},\)\{2}/&\r

Translated:

'<,'>s/X/Y     " As before
^              " Start of line
\(...\)        " A group containing:
.\{-},         " Everything up to and including the first comma
\{2}           " Match the preceding group twice (so up to and including the second comma)
&\r            " Replace with what was already there followed by a new-line

And another... given that you have equal data widths, navigate to the space before the third column of the first row. Hit Ctrl-V and go down so that you've selected the whole column of spaces (6j in your example). Press either s or Shift-i (depending on whether you want to keep the space) and then ENTER and then ESC.


Use the macros to format a line and go to the begining of the next line. Then apply that macro as may times as you need.

So, starting to record a macro is q_ where _ is a register, then edit your line, press q again to save the macro. And finally, apply it using @_ which you can prefix with a number of times you want to repeat it.


Make a recursive macro (as an alternative to @sehe's macro-for-100000-times answer).

ggqa2f,a<CR><Esc>j@aq

Then @a to run the command on the second line (you shouldn't need to move your cursor).

Visualization:

gg

Find every third value and insert cr or newline in VIM

qa

Find every third value and insert cr or newline in VIM

2f,

Find every third value and insert cr or newline in VIM

a<Cr><Esc>

Find every third value and insert cr or newline in VIM

j@aq

Find every third value and insert cr or newline in VIM

@a

Find every third value and insert cr or newline in VIM

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜