2

テキストファイルを1行ずつ処理し、それらの行内のフレーズをリンクに変換するperlスクリプトがあります(特にmediawikiマークアップでは、どのマークアップでも同じ問題が発生する可能性があります)。私が行き詰まるのは、あるフレーズが別のフレーズのサブセットである場合です。このような場合、作成されるリンクが多すぎます。

たとえば、「一般委員会」と「年次一般委員会会議」が2つのフレーズである場合:

総会は月1回開催します。

正しく変換されます:

[[#GC|一般委員会]]会議は月に1回開催されます。

でも、

年次総会は5月に開催されます。

誤って次のように変換されます:

[[#AGCM|年次[[#GC|一般委員会]]会議]]は5月に開催されます。

つまり、私のスクリプトは、「年次一般委員会会議」内で「一般委員会」というフレーズを見つけて、不要な場所にリンクを挿入しています。この例では、AGCMへのリンクのみが存在する必要があります。

関連するperlコードは次のとおりです。

my($line) = $_;
foreach $phrase (keys(%phrases))  # the phrases to replace mapped to their links
{
    my($link) = $phrases{$phrase};
    if ($line =~ m/$phrase/)
    {
        $line =~ s/$phrase/[[#$link|$phrase]]/g;
    }
}

あるフレーズが別のフレーズで見つかった場合に一致/置換を回避する方法についての提案はありますか?

更新:いくつかの質問に基づく明確化:各フレーズは独立しています。お互いに優先順位はありません。私が必要なものを手に入れるには、最短のものよりも最長のものをとるだけで十分です。

4

1 に答える 1

4

1 回の比較で任意のハッシュ キーに一致する正規表現を作成する必要があります。

このプログラムはそのアイデアを示しています。キーは長さの降順で並べ替えられるため、最長の一致が最初に検出され、次に|区切り文字として代替文字が連結されます。

次に、構築されたパターンのすべての出現箇所を見つけて、それを対応するハッシュ要素値に置き換えるだけです。これは、ループを必要とする代わりに、1 回の置換で実行できます。

空白の代わりmapに使用するa を挿入することを検討したい場合があることに注意してください。また、文字列の前後に挿入して、一致する文字列が長い単語の一部にならないようにすることもできます。また、正規表現修飾子は、大文字と小文字を区別しない一致を可能にするために関連している場合があります。\s+\b/i

use strict;
use warnings;

my %phrases = (
  'General Committee' => '[[#GC|General Committee]]',
  'Annual General Committee Meeting' => '[[#AGCM|Annual General Committee Meeting]]',
);

my $text = <<END;
The General Committee meeting shall meet once a month.
The Annual General Committee Meeting shall be held in May.
END

my $regex = join '|', sort { length $b <=> length $a } keys %phrases;

$text =~ s/($regex)/$phrases{$1}/g;

print $text, "\n";

出力

The [[#GC|General Committee]] meeting shall meet once a month.
The [[#AGCM|Annual General Committee Meeting]] shall be held in May.
于 2012-08-13T00:44:05.147 に答える