如何通过添加n +号来转换行

时间:2015-01-23 12:41:59

标签: regex vim sed vi

如何使用sed或正则表达式转换以下行?

(1,1,'country1'),(2,1,'country2'),(3,1,'country3').....

(1001,1,'country1'),(1002,1,'country2'),(1003,1,'country3')......

(1,1,'city'),(2,2,'city2'),(33,33,'city3').....

(5001,1001,'city1'),(5002,1002,'city2'),(5033,1033,'city3')......
  

我想要1000 + n所以它应该是1000 + 1 = 1001或1000 + 25 = 1025   而不是100025

4 个答案:

答案 0 :(得分:3)

vim解决方案

对于第一种情况:只有第一个数字会增加1000:

:%s/(\zs\d\+/\=submatch(0)+1000/g

对于第二个例子:必须更改两个数字,第一个数字+ 5k,第二个数字+ 1k:

:%s/\v\(\zs(\d+),(\d+)/\=string(submatch(1)+5000).','.string(submatch(2)+1000)/g 

答案 1 :(得分:0)

这是一个非常复杂的perl单行

perl -F'[(]' -ane '
    BEGIN {@add=(shift,shift)}
    print join "(", map {
        @t = split /,/,$_,-1;
        for $i (0,1) {$t[$i] += $add[$i] if $t[$i]}
        join ",", @t
    } @F
' 5000 1000 <<END
(1,1,'city'),(22,22,'city2'),(333,333,'city3')
END
(5001,1001,'city'),(5022,1022,'city2'),(5333,1333,'city3')

答案 2 :(得分:0)

通过Perl,

$ echo "(1,1,'country1'),(2,1,'country2'),(3,1,'country3')....." | perl -pe 's/\(\K(\d+)/1000+$1/eg'
(1001,1,'country1'),(1002,1,'country2'),(1003,1,'country3').....
$ echo "(1,1,'city'),(2,2,'city2'),(33,33,'city3')....." | perl -pe 's/\(\K(\d+)/5000+$1/eg;s/,\K(\d+)/1000+$1/eg'
(5001,1001,'city'),(5002,1002,'city2'),(5033,1033,'city3').....

\K会丢弃先前匹配的字符,而e修饰符有助于对替换部分执行某些算术运算。

考虑这个例子。

's/\(\K(\d+)/1000+$1/eg'
  • \(匹配文字(符号。
  • \K会丢弃之前匹配的(字符。它就像一个积极的lookebhind。 \(\K将被写为(?<=\()。下一个(\d+)会捕获以下一个或多个数字。现在这个数字存储在组索引1中。
  • 因此(加上以下数字匹配,并由此1000+$1算术运算的输出替换。请注意,$1是指位于index1组内的数字。如果存储的数字是1而不是1000+1,则会产生1001,这是替换字符串。
  • g修饰符有助于进行全局匹配。
  • e修饰符允许替换部件上的算术功能。

答案 3 :(得分:0)

嗯,这有点非常hackish(请注意,所有使用awk或sed的方法都试图绕过构建正确的解析器),但如果你的文件格式与你看起来一样严格,然后

awk 'BEGIN { RS = "("; ORS=""; FS = ","; OFS = FS } NF == 0 { next } { $1 += 5000; if(index($3, "country") == 2) $2 += 1000; print RS $0 }' filename

应该有效。那是

BEGIN { 
  RS  = "("                        # record separator
  ORS = ""                         # output record separator
  FS  = ","                        # field separator
  OFS = FS                         # output field separator
}
NF == 0 { next }                   # lines without fields skipped (that is the
                                   # virtual record before the first openparen)
{                                  # then for each line:
  $1 += 5000                       # First field increased by 5000
  if(index($3, "country") == 2) {  # Second field increased by 1000 if it
    $2 += 1000                     # describes a country
  }
  print RS $0                      # print the whole shebang
}

这需要一点解释。

由于RS(,所以记录为1,1,'country1'),2,1,'country2'),等等(最重要的是,包括最后的),

由于FS,,因此在第一条记录的示例中,字段为11'country1')和空标记。< / p>

由于ORS为空,因此awk在输出时不会在记录之间放置记录分隔符。

由于OFSFS相同,因此字段将在输出中与输入中的字段相同。

然后:

  print RS $0

打印以逗号分隔的所有字段(OFS = FS = ","),前面是openparen(这是RS),后跟输出记录分隔符 - 它是空的。因此格式保持与输入中的格式相同,只有我们更改的字段实际上已更改。