電子書籍の厳選無料作品が豊富!

文字列の否定の正規表現

次のような「File」の前の文字列を大文字に置き換えるという文で
「common」という文字列だけはそのまま置き換えないようにしたいのですが、

$string = "commonFile aaFile";
$pattern = '/(\w+)(?![common])(File)/e';
$replacement="ucwords('\\1')";
$string = preg_replace($pattern, $replacement, $string);
print htmlspecialchars($string); //Common Aa と表示される

このやり方だと「\w+」が効いてるせいなのか先読み否定の「?![common]」が効いてくれません・・・

$pattern = '/(aa)(?![common])(File)/e';
print htmlspecialchars($string); //commonFile Aa と理想とする結果が表示される

と具体的な文字列だと要求どおりになるのですが、
そうではなくて「File」の前が「common」の時だけ無視して欲しいのです。
どのように記述すれば良いのでしょうか?

A 回答 (5件)

#1の回答でも触れられてますが


>このやり方だと「\w+」が効いてるせいなのか先読み否定の「?![common]」が効いてくれません
commonを囲む[ ] はどういった意図でつけているのでしょうか?
common が続かないという先読みなら (?!common) になります。
もっともそこを直しても質問者さんの意図通りには動作しませんけど。

commonFile は commonFile のままにしておきたいけど、uncommonFile はUncommonに
したいといったことであるなら、#3の回答をちょっといじった

$pattern = '/(\w+(?<!common))(File)/e';
$replacement="ucwords('\\1')";

あたりでしょうか。
どうしても「先読み」でということなら
\b(?!common)(\w+)(File)
といった感じかと。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
そのやり方でできました。ありがとうございます。

>commonを囲む[ ] はどういった意図でつけているのでしょうか?
実は自分でもよく分からず、他の参考になるサイトなどで囲んでいたので
そのまま真似していました・・・
それと関連するかもしれないのですが、
'/(\w+(?<!common))(File)/e';

'/(\w+(?<!common))File/e';
の「File」の()なしでも成功するのですが、
自分で付けといて質問するのもあれですが、
()がある場合とない場合ではどう違うのでしょうか?
()があった方がいいのでしょうか?

お礼日時:2010/07/23 03:12

>>commonを囲む[ ] はどういった意図でつけているのでしょうか?


>実は自分でもよく分からず、他の参考になるサイトなどで囲んでいたので

んー、質問者さんが何か勘違いされていたか、そのサイトの記述が
怪しい気もします。

> それと関連するかもしれないのですが、
> '/(\w+(?<!common))(File)/e';
> は
> '/(\w+(?<!common))File/e';
> の「File」の()なしでも成功するのですが、
> 自分で付けといて質問するのもあれですが、
>()がある場合とない場合ではどう違うのでしょうか?
>()があった方がいいのでしょうか?

今回の場合は、File は( ) で囲む必要はありません。
( ) の目的は大きく二つあって、ひとつは
(common)* (common)+ のように、繰り返しの対象を大きくしたい場合です。
これを単に common* としてしまうと commonnnnn のように、最後のnだけが
繰り返しの対象になってしまいます。

もうひとつは後方参照 (back reference) で使うための記録です。
今回の例で言うと、(\w+(?<!common)) が \1 (記述上は\\1) として置換のときに
使われています。
Fileのほうはというと、そのどちらにも当てはまらないのであってもなくても
結果が変わらないのです。細かい話をすると余計に ( ) をつけて回ると
処理速度が低下するのですが、あまり神経質になる必要はありません。

とこんな感じの説明でいかがでしょうか?
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
なるほど、自分もなんとなく()があってもなくても
そんなにたいしたことじゃないだろうなぁという気がしていたのですが、
役割が分かってこれですっきりしました。

お礼日時:2010/07/23 15:26

$pattern = '/\w+(?<!common)(?=File)/e';


$replacement="ucwords('\\0')";

何か足りない気がするけどまぁいいか。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
このやり方だと、
//commonFile AaFile
とAaにもFileが残ってしまいますが
//commonFile Aa
とcommon以外はFileはなくしたいです。

お礼日時:2010/07/22 16:09

たとえば抜き出したあとにチェックするとか?



<?
$string = "commonFile aaFile";
$pattern = '/(\w+)(File)/e';
$replacement="('\\1'=='common')?'\\1':ucwords('\\1')";
$string = preg_replace($pattern, $replacement, $string);
print htmlspecialchars($string); //common Aa と表示される
?>
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
なるほど、(正しい言い方かわかりませんが)正規表現以外の部分で
処理してしまおうということどね。
たしかにこのやり方なら、使い慣れてる分自由にできそうですね。

ところで正規表現の分野において文字列の否定については、
あまり取り扱ってないというか(なんとなくですが)消極的な気がするのですが
何か理由みたいなのはあるのでしょうか?

お礼日時:2010/07/21 16:09

[common] が文字クラスとして解釈されてたりして.


あと, なんとなく「先読み」を誤解しているような気がしないでもない.
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!