Вопрос

My question is about parsing and making changes to strings in VIM. It is three-fold:

  1. How can I, given a string of digits, replace each digit for another one?

    for instance, replacing 1 with 3, 2 with 1, and 3 with 2: 123 becomes 312

  2. Once accomplished, how can I reorder the digits in a string in numerical order?

    for instance, 541, 203 becomes 145, 023

  3. And then, rearrange the strings in numerical order?

    for instance, 234, 012, 345, 123, becomes 012, 123, 234, 345

Here is an example line:

025, 056, 125, 235, 256, 257

As you can see, each number in an element is properly ordered, and the elements are ordered as well. However, I need to replace each digit as follows:

0 -> 2
1 -> 3
2 -> 6
3 -> 7
4 -> 0
5 -> 1
6 -> 4
7 -> 5

Once accomplished, the numbers of each element will be out of order, as will the elements themselves. I will then need to complete steps 2 and 3 to create a 'proper' new list of elements.

There are many replacement schemes that I need to accomplish for many different lines. To do this by hand would take long, and is error prone.

Finally, when steps 1-3 are finished for all schemes for all lines, step 4: delete the duplicate arrangements. This is trivial if steps 2-3 were accomplished.

How can I get VIM to do this for me? Is it even possible to do this kind of text-editing?

Это было полезно?

Решение

Use \= in the :s replacement part to execute vim expressions.

:%s/\d\+/\=join(sort(split(tr(submatch(0), '01234567', '23670145'), '\zs')), '')/g
:%s/.*/\=join(sort(split(submatch(0), ', ')), ', ')

You could also use Tim Pope's Abolish plugin for the :Subvert command for instead of tr(). e.g. :%S/{0,1,2,3,4,5,6,7}/{2,3,6,7,0,1,4,5}/g

For more help see:

:h :s\=
:h sort(
:h join(
:h split(
:h tr(

Другие советы

To get you started, step 1 is typically the job of shell command tr, which exists in vim as a function:

:let @q=tr(expand("<cword>"), "0123", "2367")

will store in register q the modified version of the number under the cursor. However it is not a Vim command, so you have to write a function to use this. Perl or python may be more appropriate than Vim for your purpose.

I concur that it is probably more trouble than it's worth to do this in vim. Here's a full solution using common commandline tools:

#!/bin/sh

echo "025, 056, 125, 235, 256, 257" |
tr 01234567 23670145 | awk -F", " '{
    for (i=1; i<=NF; i++) {
        split($i, digits, "")
        n=asort(digits)
        for (x=1; x<=n; x++) {
            printf("%s",digits[x])
        }
        printf("\n")
    }
}' | sort -n |
sed ':a;N;$!ba;s/\n/, /g'
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top