0

このウェブサイトは初めてです。これは、2時間以上私を悩ませた問題です。次のような文字列 (newick 形式の系統樹) があります。

((A:14,B:43):22,C:76,(D:54,(E:87,F:28):17):35);

ツリーには複数のレベルがあり、括弧で示されます。ここで、最上位の数値 (枝の長さ) に数値、たとえば 10 を追加します。ここには、22、76、35 の 3 つの最上位レベルの数値しかありません。変換後、文字列は次のようになります。

((A:14,B:43):32,C:86,(D:54,(E:87,F:28):17):45);

適切な正規表現を考え出すために最善を尽くしましたが、最終的に自分の限界を認めました。どうすれば本当にできるのでしょうか?

4

4 に答える 4

1

これには、ネストされた括弧に一致する再帰的な正規表現が必要です。

最初に「キー」を定義します。これは、大文字の文字列、または括弧内の任意の数のキーと値のペアのいずれかです。

次に、すべてのキーの後にコロンと 10 進数が続くのを見つけ、その数値に対して算術演算を行います。

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)
于 2012-07-31T15:56:26.600 に答える
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)ます。

トップダウンの再帰的解析のための小さな文法を定義します。必要に応じて変更してください。最上位には、興味のないプレ要素があり、これを格納し$1ます。これらは、単一の文字または括弧で囲まれたツリーにすることができます。a の後に:は、インクリメントする数値が続き、 に格納され$2ます。その後に、文字列の末尾またはカンマが続きます。最後の一致が残ったところから始めて、反復的に一致します (/gオプションと\Gアサーションによって記号化されます)。追加は、置換文字列を作成するときに発生します (/eオプションを使用しています)。

于 2012-07-31T14:50:44.053 に答える
1
s/(?:^\(|(\((?:(?>[^()]*)|(?1))*\)))\K|:\K([0-9]+)/$2?$2+10:""/ge

スキップしたいもの、または : で始まる数字のいずれかに一致します。

スキップしたいものは、先頭(またはバランスのとれた括弧のセットです (バランスの取れた括弧はほぼ文字通りperlreから取られた正規表現です)。

置換では、変更する数字が一致した場合は 10 を追加し、そうでない場合は何も一致しません。

しかし、賢くならずに、ツリーの解析、変更、および再シリアル化の作業に取り掛かる方が賢明です。

于 2012-07-31T14:51:31.683 に答える
0

まず、このスレッドに非常に興味深い投稿をしてくれた ysthに感謝します。\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)
于 2012-07-31T17:44:45.347 に答える