1

i18nメッセージを検索するためにプロジェクトのすべてのファイルを読み取るタスクを(PHPで)構築しています。次のようなメッセージを検出したい:

// Basic example
__('Show in English')  => Show in English
// Get the message and the name of the i18n file 
__("Show in English", array(), 'page') => Show in English, page
// Be careful of quotes
__("View Mary's Car", array()) => View Mary's Car
// Be careful of strings after the __() expression
__('at').' '.function($param) => at

これらのケースで機能する正規表現(他にもいくつかのケースが考慮されています)は次のとおりです。

__\(.*?['|\"](.*?)(?:['|\"][\.|,|\)])(?: *?array\(.*?\),.*?['|\"](.*?)['|\"]\)[^\)])?

ただし、式が複数行にある場合は機能しません。dotailを含める必要/sがありますが、先を見据えるタイミングを適切に制御できないため、以前の正規表現が壊れます。

// Detect with multiple lines
echo __('title_in_place', array(
    '%title%' => $place['title']
  ), 'welcome-user'); ?>    

問題を解決し、開閉括弧に一致する正規表現を単純化することが1つあります。したがって、中身__()や括弧の数に関係なく、開始数を「カウント」し、その数の終了数を予測します。

出来ますか?どのように?どうもありがとう!

4

4 に答える 4

2

はい。まず、単純なネストされた角かっこ(括弧)の典型的な例を次に示します。

\(([^()]|(?R))*\)

または所有格数量詞を使用するより高速なバージョン:

\(([^()]++|(?R))*\)

または(同等の)アトミックグループ化:

\((?>[^()]+|(?R))*\)

(?R) ただし、ここでは「式全体に一致」式を使用できません。これは、最も外側の角かっこが特殊であるためです(2つの先頭の下線が付いています)。これがあなたが望む(私が思うに)一致するテストされたスクリプトです...

解決策:グループ$1(再帰)サブルーチン呼び出しを使用します。(?1)

<?php // test.php Rev:20120625_2200
$re_message = '/
    # match __(...(...)...) message lines (having arbitrary nesting depth).
    __\(                     # Outermost opening bracket (with leading __().
    (                        # Group $1: Bracket contents (subroutine).
      (?:                    # Group of bracket contents alternatives.
        [^()"\']++           # Either one or more non-brackets, non-quotes,
      | "[^"\\\\]*(?:\\\\[\S\s][^"\\\\]*)*"      # or a double quoted string,
      | \'[^\'\\\\]*(?:\\\\[\S\s][^\'\\\\]*)*\'  # or a single quoted string,
      | \( (?1) \)          # or a nested bracket (repeat group 1 here!).
      )*                    # Zero or more bracket contents alternatives.
    )                       # End $1: recursed subroutine.
    \)                      # Outermost closing bracket.
    .*                      # Match remainder of line following __()
    /mx';
$data = file_get_contents('testdata.txt');
$count = preg_match_all($re_message, $data, $matches);
printf("There were %d __(...) messages found.\n", $count);
for ($i = 0; $i < $count; ++$i) {
    printf("  message[%d]: %s\n", $i + 1, $matches[0][$i]);
}
?>

このソリューションは__(...)、任意の深さ(ホストメモリによってのみ制限される)までのバランスの取れた括弧( ""構造内)を処理することに注意してください。また、 " __(...)"内の引用符で囲まれた文字列を正しく処理し、これらの引用符で囲まれた文字列内に表示される可能性のある括弧を無視します。幸運を。*

于 2012-06-26T00:38:28.673 に答える
1

正規表現ではバランスの取れた括弧を一致させることはできません(非標準の非正規表現を持つエンジンを使用しない限り、それでもそれは悪い考えであり、維持するのは難しいでしょう)。

正規表現を使用して一致する可能性のある行を検索し、一致する閉じ括弧のインデックスが見つかるまで、開き括弧と閉じ括弧の数を文字ごとに数えて文字列文字を反復処理できます。

于 2012-06-25T16:28:57.650 に答える
1

私にとってはそのような表現を使う

(\(([^()]+)\))

私はそれを見つけてみます

 * 1) (1+2)
 * 2) (1+2)+(3+2)
 * 3) (IF 1 THEN 1 ELSE 0) > (IF 2 THEN 1 ELSE 1)
 * 4) (1+2) -(4+ (3+2))
 * 5) (1+2) -((4+ (3+2)-(6-7)))
于 2017-01-12T13:43:24.127 に答える
0

私がこれをやってのけることを知っている唯一の方法は、バランスの取れたグループ定義を使うことです。これは正規表現の.NETフレーバーの機能であり、この記事で非常によく説明されています。

また、Qtaxが指摘しているように、これはPCREで(?R)ドキュメントに記載されているとおりに実行できます。

または、カスタムパーサーを作成することでこれを実現することもできます。ParenthesesCount基本的には、左から右に解析しているときに呼び出される変数を維持するという考え方です。ParenthesesCount表示するたびにインクリメント(し、ごとにデクリメントします)。私は最近、ネストされた括弧をこのように処理するパーサーを作成しました。

于 2012-06-25T16:34:39.353 に答える