1

Let's say I have a file that looks like:

host[1-2]lx
host[1-4]win

what I want is an easy way to get

host1lx
host2lx
host1win
host2win
host3win
host4win

Is there a neat way to automate that process?

Edit: What I was hoping for is something like using a substitution on host[1-4]win using the line number, where I can repeat the replacement using the [1-4] part. Imagine something like

:110s_host\[1-4\]win_host1win\rhost2win\rhost3win\rhost4win\r_

But is there a way to not spell out the four hosts, instead have sed repeat it based on what was found in the [...]?

4
  • 1
    What did you try?
    – romainl
    Sep 20, 2023 at 4:48
  • 1
    Regular expressions work the other way around. They match existing strings, they don't generate them. Also, all you want is a tiny subset of regular expressions; i.e. you don't want to extend .*. Overall, this sounds more like a task for a scripting language than for an editor. If you run into problems scripting a solution, ask on SO. I'm voting to close as off-topic.
    – Friedrich
    Sep 20, 2023 at 6:18
  • @romainl I had not tried much because I don't even know where to start. So far I had been doing it by making N number of copies manually, and then using the line numbers in a substitution. For example. if the N is at the end, and the line numbers are 112 to 116, I would remove the sqr brackets stuff and do 112,116s/$/\=line('.')-111/
    – deedar huq
    Sep 20, 2023 at 19:11
  • @Friedrich, oh gotcha, thanks. Makes sense I guess. I somehow assumed there has got to be a Vim way of doing this easily
    – deedar huq
    Sep 20, 2023 at 19:14

1 Answer 1

1

I doubt a simple solution exist for any regular expression but for you case you could:

Define the following function:

function! GenerateLineRange(start, end, i1, i2)
    let ret = ''
    for i in range(a:i1, a:i2)
        let ret = ret . a:start . i . a:end
        if i != a:i2
          let ret = ret . "\n"
        endif
    endfor
    return ret
endfunction

Use it in a substitution:

:%s/\v(.*)(\[(\d+)-(\d+)\])(.*)/\=GenerateLineRange(submatch(1), submatch(5), submatch(3), submatch(4))
5
  • 1
    Oh wow, that is extraordinary, it works! Thank you so much! And it is very readable, I get it. Never seen a Vim function before, so I just learnt something massive. Thanks again!
    – deedar huq
    Sep 20, 2023 at 19:25
  • One question, what is the \v in the beginning?
    – deedar huq
    Sep 20, 2023 at 19:34
  • 1
    @deedarhuq \v turns on very magic mode, see :help /\v. It's used to type fewer backslashes to escape special characters.
    – Friedrich
    Sep 20, 2023 at 20:25
  • Thanks for the feedback :-) Welcome to Vim ;-) Sep 20, 2023 at 21:07
  • 1
    Thanks to both of you! VivianDeSmedt and @Friedrich
    – deedar huq
    Sep 23, 2023 at 18:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.