1

Is it possible to transform:

John Apple Red 3 John Apple Green 5 John Radish White 2 John Radish Red 7 Tom Apple Red 3 Tom Apple Green 5 Tom Radish White 2 Tom Radish Red 7 

to:

John Apple Red 3 Green 5 Radish White 2 Red 7 Tom Apple Red 3 Green 5 Radish White 2 Red 7 

using Vim?


I have a large block of configurations (~10k). Each one is something like

Criterion1=1A Criterion2=2A Criterion3=3A... ConfigItem=valA Criterion1=1A Criterion2=2A Criterion3=3B... ConfigItem=valB Criterion1=1A Criterion2=2B Criterion3=3C... ConfigItem=valC Criterion1=1A Criterion2=2B Criterion3=3D... ConfigItem=valD Criterion1=1B Criterion2=2E Criterion3=3F... ConfigItem=valE 

I'm hoping to simplify the presentation to better understand it. Here's an example:

Criterion1=1A Criterion2=2A Criterion3=3A... ConfigItem=valA Criterion3=3B... ConfigItem=valB Criterion2=2B Criterion3=3C... ConfigItem=valC Criterion3=3D... ConfigItem=valD Criterion1=1B Criterion2=2E Criterion3=3F... ConfigItem=valE 

The format I've demonstrated above (replacing common repeated prefixes with spaces) would also help make folding work.

4
  • 1
    What did you try? Commented Sep 13, 2023 at 5:42
  • [[1]] It is not "characters" , it should be "words" [[2]] You should include why you want to try this , because there might be "better" ways to achieve that Commented Sep 13, 2023 at 11:53
  • i dump from a piece of code a bunch of configurations (>10k), each one is something like Criterion1=Value1 Criterion2=Value2 Criterion3=Value3 ... -> ConfigName=ConfigValue, now it's a long txt file, somewhat overwhelming, I'm looking to simplify it as the example above, what's more, the blank spaces would help in folding as i'm using vim. Commented Sep 13, 2023 at 17:03
  • @romainl I don't know how to start, not familiar with (advanced) regex. honestly Vivian's answer I don't quite get how the (.*) part matched the next line. currently I'm only using block editing to select some rows with common starting words, and then r to replace that part with space. Commented Sep 13, 2023 at 17:06

1 Answer 1

1

I would run the following commands:

:g/^./move 0 :%s/\v^(.*)\ze.*\n\1/\=substitute(submatch(1), '.', ' ', 'g') :g/^./move 0 
  1. g/^./move 0 moves the text upside down. Since the logic has to run from bottom to top but substitution only works from top to bottom I first move the buffer upside down.

  2. s/\v^(.*)\ze.*\n\1 splits the current line into: the part that is in common with the next line ((.*)) and the part that is not (.*)

    Remark: I use \ze to:

    1. avoid that the pattern eats part of the next line, otherwise the substitution will apply only on one line out of two and
    2. avoid it eats the second part of the line such that we don't need to replace it.
  3. substitute(submatch(1), '.', ' ', 'g') replaces every character of the first part by a space

  4. g/^./move 0) restores the lines in the right order.

7
  • 2
    Let me guess, you're going to add an explanation of what this does after it gets accepted? Commented Sep 13, 2023 at 6:05
  • 1
    No I publish a first version quickly for the impatient :-) Commented Sep 13, 2023 at 6:11
  • i might be asking too much, is it possible to make the comparision not by characters but by word? Commented Sep 13, 2023 at 16:22
  • I thought about it but it is for sure more complex and probably require more command. If I find a solution I'll post it ;-) Commented Sep 13, 2023 at 16:34
  • @VivianDeSmedt could you pls elaborate, how the (.*) matches with the next line? i thought it matches everything until the next part Commented Sep 13, 2023 at 17:09

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.