ページ

2012/12/08

[競技プログラミング][PHP][DigitalArts プログラミングコンテスト2012]C-Filter

A - C-Filter

時間制限 : 2sec / スタック制限 : 64MB / メモリ制限 : 64MB

問題文

セキュリティに興味がある高橋君は、デジタルアーツ株式会社に就職したい青年です。
彼は、面接で自分をアピールするために、
得意なプログラミングでフィルタリングソフト「C-Filter」を作ろうと考えています。
「C-Filter」は、与えられた文字列 s に、
あらかじめ登録しておいた「NGワード」と一致する文字列が存在する場合、
その文字列の長さと等しい数の *に置き換えて出力するソフトウェアです。
この文字列を置き換える処理をフィルタリングと呼びます。
「NGワード」とは、半角英小文字と*から構成されます。
*はすべての半角英小文字 1 文字と一致します。
例えば myonmyon は、NGワードmyo*myonと一致します。
ただし、NGワードは単語ごとに適用されるため、myo myon はNGワード myo*myonとは一致しません。
また、NGワードはある単語に対して完全に一致する必要があります。
例えば、abcdeは、NGワードabcやbcd、cdeに一致しません。

文字列 s と、NGワードが与えられるので、C-Filterの出力する文字列を答えてください。

入力

入力は以下の形式で標準入力から与えられる。
s
N
t1
:
:
tN
入力は N+2 行からなる。
1 行目には 1 文字以上 1,000 文字以下の文字列 s が与えられる。
s はフィルタリングする対象の文字列を半角スペースで区切って繋げた文字列である。
2 行目にはNGワードの個数を表す整数 N(0≦N≦50) が与えられる。
3 行目から N+2 行目までNGワードを表す文字列 ti(1≦i≦N)が与えられる。
文字列 ti は半角英小文字と * から構成される。
文字列 ti の長さは 1 文字以上、 20 文字以下である。
文字列 ti に含まれる * は、半角スペースを除くすべての半角英小文字 1 文字をフィルタリングの対象とします。

出力

入力された文字列 s をC-Filterでフィルタリングした結果を 1 行で出力せよ。
なお、最後には改行を出力せよ。

出典

A: C-Filter - DigitalArts プログラミングコンテスト2012 | AtCoder

回答

AtCoder/digitalarts_1.php at master · wada811/AtCoder · GitHub
<?php
$sentence = trim(fgets(STDIN));
fscanf(STDIN, "%d", $n);
$filters = array();
for($i = 0; $i < $n; $i++){
    $filters[] = '/^' . str_replace('*', '.', trim(fgets(STDIN))) . '$/';
}
$words = explode(' ', $sentence);
$censored = preg_replace_callback(
                $filters,
                create_function(
                    '$matches',
                    'return str_repeat("*", strlen($matches[0]));'
                ),
                $words
            );
echo implode(' ', $censored) . PHP_EOL;
?>
fgetsで1行取得。この際にtrimしておかないと思わぬ改行コードでハマる。
6行目で取得しつつ正規表現に入れ込む。 間の空白を置換しないようにするのが面倒なので空白で分割。 preg_replaceのe修飾子が PHP 5.5.0 で非推奨になったので
AtCoder の PHP のバージョンは 5.3.6だけど使わないでおく。
代わりにpreg_replace_callbackでうまいことやる。
第二引数のコールバック関数にマッチした文字の文字数だけstr_repeatで繰り返す。
後は文字列に直して出力!テクニカルな感じでカッコいい!