1

I have a C program where I have to change a 2D array into a 1D array.

What I want is to change this code:

temp[i][j] = (Grid[i][j-1] + Grid[i][j] + Grid[i+1][j] + Grid[i][j+1])/5

to this one:

temp[i*PPE+j] = (Grid[i*PPE+j-1] + Grid[i*PPE+j] + Grid[(i+1)*PPE+j] + Grid[i*PPE+j+1])/5

Because I'm new to Vimscript I split the problem into two parts and tried to tackle the first one:

  • [i][j] -> [i*PPE+j]
  • [i+1][j+1] -> [(i+1)*PPE+j+1]

I tried the following until now:

:%s#\v[^0-9](\]\[)[a-z][^-+]#\=substitute("\1","*PPE+", "", "")#gc

My reasoning behind this:

  • :%s#\v: go through whole file and use magic
  • [^0-9](\]\[)[a-z][^-+]: match <nonumber>][<char><not+or-> and () for establishing a group
  • \=substitute("\1","*PPE+", "", ""): substitute the first group ( ][ ) with *PPE+
  • gc: g for all matches in one line and c for confirmation query

Unfortunately this doesn't seem to work as it replaces i][j] with ^A

Any help with this would be greatly appreciated!

2
  • 1
    I did not try it. But one thing I noticed immediately is that you cannot use so called sub-replace-specials ie. \1 after \=. This should be submatch(1). This is mentioned under :h sub-replace-expression.
    – Hotschke
    Commented Nov 20, 2018 at 15:58
  • I tried this too but then it replaces [i][j]with [][
    – TheKaltur
    Commented Nov 20, 2018 at 16:03

1 Answer 1

3

Update

Again, I'm not sure if I fully understand your goal, but the following two commands convert your "before" into your "after":

Handle the i+1 case:

:%s/\v(\D[+-]\d)\]\[/(\1)*PPE+

Do all the rest:

:%s/]\[/*PPE+/g

The first command replaces:

<not-a-digit><plus-or-minus><digit>][

with:

(<captured-group>)*PPE+

The second command simply replaces all remaining instances of ][ with *PPE+.

Original Answer regarding [i][j] only

If I understand your question rightly, I'm not sure if using a sub-replace-expression is the best tool for this job. Perhaps \zs and \ze are better suited to the task?

Try this command:

:%s/\v\D\zs\]\[\ze\D\]/*PPE+

It converts this:

[i][j]
[i+1][j]
[i][j+1]
[i+1][j+1]

To this:

[i*PPE+j]
[i+1][j]
[i][j+1]
[i+1][j+1]

...by matching <not-a-digit>][<not-a-digit>], but setting only the ][ to be included in the match.

Notes:

  • \D is easier to type than [^0-9]
  • I'm matching a closing ] rather than <not-plus-or-minus>
4
  • Thank you very much, this is a good answer. What I was looking for is the part with \zs and \ze. Can you tell me what is wrong with my approach above? I'm looking to learn how to make this more scriptable and afair \zs and \ze only work if you have one submatch.
    – TheKaltur
    Commented Nov 20, 2018 at 17:21
  • What your command is doing is replacing your match with the result of your substitute() call. After making the correction suggested by @Hotschke your substitute call boils down to substitute("][", "*PPE+", "", ""), which means "in the string ][ substitute *PPE+ with the empty string. *PPE+ does not appear in the string ][, so this always returns ][.
    – Rich
    Commented Nov 20, 2018 at 17:34
  • I think you probably want something more along the lines of substitute(submatch(0), "][", "*PPE+"), but I haven't tested that.
    – Rich
    Commented Nov 20, 2018 at 17:36
  • @TheKaltur No probs. Glad I could help!
    – Rich
    Commented Nov 20, 2018 at 19:35

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.