我是这个网站的新手。这是一个困扰我> 2小时的问题。我有一个字符串(newick格式的系统发育树),看起来像:
((A:14,B:43):22,C:76,(D:54,(E:87,F:28):17):35);
树可能有多个级别,用括号表示。现在我想在顶级数字(分支长度)中添加一个数字,比方说10。这里只有三个顶级数字:22,76,35。转换后,字符串应如下所示:
((A:14,B:43):32,C:86,(D:54,(E:87,F:28):17):45);
我已经尽力了解正确的正则表达式,但终于承认了我的限制。怎么能真的做到?
答案 0 :(得分:1)
虽然我会选择解析整个树,但只使用正则表达式可以解决问题:
use strict; use warnings; use feature qw(say);
my $string = "((A:14,B:43):22,C:76,(D:54,(E:87,F:28):17):35)";
$string =~ s/^\(//;
$string =~ s/\)$//;
$string =~ s{
\G ((?&PRELEM)) : (\d+) (,|$)
(?(DEFINE)
(?<SUBLIST> [(] (?&ELEM)(?:,(?&ELEM))* [)] )
(?<ELEM> (?&PRELEM) : \d+ )
(?<PRELEM> (?:[A-Z]|(?&SUBLIST)) )
)
}{"$1:".($2+10).$3}gex;
say "($string)";
打印((A:14,B:43):32,C:86,(D:54,(E:87,F:28):17):45)
。
我为自上而下的递归解析定义了一个小语法,请根据需要进行调整。在顶层,我们有无趣的Pre-Elements,我们存储在$1
它们可以是一个单个字母或括在括号中的树。在:
到达我们想要增加的数字后,存储在$2
中。接下来是字符串或逗号的结尾。我们迭代匹配,从最后一个匹配的位置开始(由/g
选项和\G
断言表示)。当我们构建替换字符串时,会发生添加(我们正在使用/e
选项)。
答案 1 :(得分:1)
s/(?:^\(|(\((?:(?>[^()]*)|(?1))*\)))\K|:\K([0-9]+)/$2?$2+10:""/ge
匹配要跳过的内容或前面带有数字的数字:。
您要跳过的内容可以是前导(
或任何平衡的括号(平衡括号正则表达式几乎完全取自perlre)。
在替换中,如果要修改的数字匹配则添加10,否则不匹配。
但是你最好不要聪明,而是去工作来解析,修改和重新序列化你的树。
答案 2 :(得分:1)
这需要一个递归的正则表达式来匹配嵌套的括号。
首先定义一个'key',它是一串大写字母或括号之间的任意数量的key:value对。
然后找到所有键后跟冒号和十进制数字,然后对数字进行arithemtic。
use strict;
use warnings;
my $str = '((A:14,B:43):22,C:76,(D:54,(E:87,F:28):17):35)';
my $key = qr/ (?<key> [A-Z]+ | \( (?&key) : \d+ (?: , (?&key) : \d+ )* \) ) /x;
$str =~ s/$key : \K ( \d+ ) /$2 + 10/xge;
print $str;
<强>输出强>
((A:14,B:43):32,C:86,(D:54,(E:87,F:28):17):45)
答案 3 :(得分:0)
首先,我要感谢此帖子中的ysth for his very interesting posting。从这篇文章中,我了解了如何以及为何应用\K
eep修饰符。
我添加了另一个\K
(到第一个子表达式)并对原子组使用了新的++
表示法:
my $r = qr{
(?:
(?: ^ \(\K )
|
(
\( (?: [^()]++ | (?1) )* \)
)\K
)
|
:\K (\d+)
}x;
输出字符串现在与输入字符串完全匹配 - 除了递增的值:
$t =~ s/$r/$2?$2+10:''/ge;
input: ((A:14,B:43):22,C:76,(D:54,(E:87,F:28):17):35)
output: ((A:14,B:43):32,C:86,(D:54,(E:87,F:28):17):45)