3

Considering this type of Json structure :

[
    {
        "id": "0000000000001",
        "en-US": "String 1"
    },
    {
        "id": "0000000000002",
        "en-US": "String 2"
    }
    ...
]

I want to get this structure:

[
    {
        "id": "0000000000001",
        "en-US": "String 1",
        "en-GB": "String 1",
        "fr-FR": "String 1"
    },
    {
        "id": "0000000000002",
        "en-US": "String 2",
        "en-GB": "String 2",
        "fr-FR": "String 2"
    }
    ...
]

Right now I am able to duplicate the lines with:

:g/en-US/t.

 [
        {
            "id": "0000000000001",
            "en-US": "String 1",
            "en-US": "String 1"
        },
        {
            "id": "0000000000002",
            "en-US": "String 2",
            "en-US": "String 2"
        }
        ...
    ]

I tried to concatenate that with sed to replace the string used as regex (en-US) for one of the goals without getting it worked.

How could I do the duplicate and replace together?

1
  • 1
    Using a macro would make this straightforward.
    – B Layer
    Aug 3, 2017 at 9:21

2 Answers 2

5

If you're willing to use one command by language you can do this:

g/en-US/t.|s/en-US/en-GB
g/en-GB/t.|s/fr-FR/en-GB

As you can see we reuse your command, and add another one to be executed with the | character.

Edit As suggested in the comments (Thank you @Doktor OSwaldo!) it is possible to put the command in a loop to avoid using it several time:

let lang=['en-GB','fr-FR'] | for i in lang | execute 'g/en-US/t.|s/en-US/'.i | endfor

Otherwise you can use a macro:

First put en-US in your search register with /en-US<CR>

Then record your macro:

qqnYpci"en-GB<Esc>Ypci"fr-FR<ESC>q

We can decompose it like this:

qq              Start recording in the register q
n               Go to the next occurence of the search (i.e "en-US")
Yp              Duplicate the line
ci"             Modify the content of the quotes
en-GB<Esc>      Put in the quotes 'en-GB' and exist insert mode
Yp              Duplicate the line
ci"             Modify the content of the quotes
fr-FR<Esc>      Put in the quotes 'fr-FR' and exist insert mode
q               stop recording the macro

You can then replay the macro as many times as you have lines that you want to duplicate.


Edit: If you want to call the macro only once (instead of specifying how many times it must be executed) you can use a recursive macro:

Firs you need to empty the register which will contain the macro (by recording an empty macro):

qqq

Then use the same macro but add @q at the end, this way the macro will call itself:

qqnYpci"en-GB<Esc>Ypci"fr-FR<ESC>@qq

One important detail is to use set nowrapscan this will make the macro fail when it execute the search after the last occurence in the file. Otherwise the macro will loop infinitely in the file and you'll get a lot of duplicate lines. See :h 'nowrapscan'.

9
  • Does the macro gets executed globally or do I have to execute it ocurrence by ocurrence?
    – Dez
    Aug 3, 2017 at 9:29
  • It'll be repeated however many times you specify, e.g. 10@q will repeat 10 times. Go to the top of the file, execute the search, play the macro as many times as blocks/ids you have.
    – B Layer
    Aug 3, 2017 at 9:32
  • 2
    @Dez if you need to do this for a lot of languages, you can pack the first solution from statox in a for loop: :let lang=['en-GB','fr-FR'] | for i in lang | execute 'g/en-US/t.|s/en-US/'.i | endfor just insert all languages you want into the lang list. Aug 3, 2017 at 10:45
  • 1
    Yup sorry for the typo in my macros I don't know how I messed that up, thanks for the edit.
    – statox
    Aug 3, 2017 at 12:05
  • 2
    @statox please feel free to add my line to your answer if you like. Since i have taken everything except a dumb for loop from your answer, I won't write a own answer. Aug 3, 2017 at 12:22
0

If you want to do this without sed running over the text multiple times, you can use the sed "hold space" to save the line and then make replacements and print the modified line:

sed -e "\
    /en-US/{h;\
        x;h;s/en-US/en-US/;p;\
        x;h;s/en-US/en-GB/;p;\
        x;h;s/en-US/fr-FR/;p;\
    d;}"

(this example uses line continuationations to make it easier to see what is going)

Your Answer

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

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