質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.49%

  • PHP

    20765questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • Java

    14056questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

正規表現で『「abc」と言う塊以外の文字列』は指定できるか

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 9
  • VIEW 3,510

uer03108

score 93

正規表現について、質問です。

例えば、下記の様な文字列を考えます。

aeeebbdddabccccffff

この時、正規表現が

reg = "/[^abc]+/";

であれば、「a, b, c」以外になるので、

res = "eeedddffff";

になります。

質問なのですが、『「abc」と言う塊以外の文字列』は指定できるのでしょうか。

preStr = "aeeebbddd「abc」cccffff";

resStr = "aeeebbdddcccffff";

となる様な正規表現になります。


補足

多くの回答、有難うございました。
読み返してみると言葉足らずでしたので、補足させて頂きます。
恐らく、CertaiN様の方法でいけそうな気がします。

正直に言うと、CodeIQであった問題です。
頭に引っかかっていたので質問させて頂きました。

例えば、
I am Tom. He is Mr. Smith.

と言う文章が1行であるとします。
この文章を

I am Tom.
He is Mr. Smith.

の2つに分ける場合、単純に「.」でsplitするとMr.の部分も分割されてしまいます。
なので、
 「Mr.」は除いて、「.」で分ける
と言う処理が必要になりますが、
 /[^Mr.]+[\.]/
にすると、質問の通り上手く動作しません。なので、「Mr.」と言うブロックを除く処理が調べておりました。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+6

まず前提として,この回答においては文字列ではなくバイト列という表記にします.日本語を相手にしても本当に1文字という単位で見てくれるのはu修飾子をつけたpreg_*系の関数,あるいは文字コードをUTF-8として正しく指定したmb_*系の関数のみです.残りの関数は全てバイト単位で計算します.

本題に入ります.既に回答にありますが,除外したいバイト列を空白に置換して残ったバイト列を得るというアプローチにてpreg_replaceあるいはpreg_replace_callbackを使って済むのであればそれが一番簡単です.正規表現無しでも簡単に書ける範囲であればstr_replacestrtrを使うほうがよいでしょう.なお文字コードがUTF-8である場合は,正規表現の文字クラス[]を使わない限り,「文字列=バイト列」のように扱っても正しく動作します.このことは上にリンクしたQiitaの記事でも解説しています.

<?php

$str = 'ライスパスタカレーパスタドリア';

echo str_replace('パスタ', '', $str), "\n"; // ライスカレードリア

但しこれらには,複数の置換を同時に行う際に微妙な違いがあるので注意してください.以下を実行してみるとわかります.

<?php

$str = 'ライスパスタライスカレーライスカレードリア';

print_r([

    'str_replace' => str_replace(
        ['カレーライス', 'カレー', 'ライス'],
        ['【カレーライス】', '【カレー】', '【ライス】'],
        $str
    ), // 【ライス】パスタ【ライス】【【カレー】【ライス】】【カレー】ドリア

    'strtr' => strtr($str, [
        'カレーライス' => '【カレーライス】',
        'カレー' => '【カレー】',
        'ライス' => '【ライス】',
    ]), // 【ライス】パスタ【ライス】【カレーライス】【カレー】ドリア

    'preg_replace (複数の正規表現で処理)' => preg_replace(
        ['/カレーライス/', '/カレー/', '/ライス/'],
        '【$0】',
        $str
    ), // 【ライス】パスタ【ライス】【【カレー】【ライス】】【カレー】ドリア

    'preg_replace (単一の正規表現で処理)' => preg_replace(
        '/カレーライス|カレー|ライス/',
        '【$0】',
        $str
    ), // 【ライス】パスタ【ライス】【カレーライス】【カレー】ドリア

]);

strtr preg_replace (単一の正規表現で処理) においては一度置換したところを次回の置換対象から外してくれますが, str_replace preg_replace (複数の正規表現で処理) においては全く考慮してくれません. 速度面においても,僅かな違いですが,一般的には速い順に

  1. str_replace
  2. strtr (実はもう1つ使い方があるがこの例のように連想配列で置換する場合)
  3. preg_replace (単一の正規表現で処理)
  4. preg_replace (複数の正規表現で処理)

として差がつくと思うので,書きやすさも考慮して適宜使い分けてください.

また正規表現の高度なテクニックですが,バックトラッキングコントロールを使うとまさに「あるバイト列以外のバイト列」を直接マッチさせることもできます.

<?php

$str = 'ライスパスタライスカレーライスカレードリア';

echo preg_replace(
    '/(?:カレー|ライス)(*SKIP)(*FAIL)|.+?(?=カレー|ライス|\z)/s',
    '【$0】',
    $str
), "\n"; // ライス【パスタ】ライスカレーライスカレー【ドリア】

上記の例では

  1. まず現在位置から「カレー」「ライス」いずれかにマッチするバイト列を探す.マッチしたら何も無かったことにして3に進む.マッチしなければ2に進む.
  2. 後ろに「カレー」「ライス」「末尾」のいずれかが来るように,1バイト以上の可能な限り短いバイト列を探す.マッチしたら置換処理を行う.マッチしなければ3に進む.
  3. 現在位置を今マッチさせたバイト列のぶんだけ進める.マッチしていなければ1バイト進める.
  4. まだ後ろに1バイト以上あれば1に戻る.無ければ終了する.

という処理を行っています.


【追記】

コメントにも書きましたが,こちらにも最終目的のコードをシンタックスハイライトをつけて書いておきます.

<?php

$str = 'I am Tom. He is Mr. Smith.';
$sentences = preg_split('/(?:Mr|Mr?s|Dr|Sir|Prof)\.(*SKIP)(*FAIL)|\.\K\s+/', $str);
var_dump($sentences);

/*
array(2) {
  [0]=>
  string(9) "I am Tom."
  [1]=>
  string(16) "He is Mr. Smith."
}
*/

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/31 12:40

    勉強になりました。
    有難うございます。

    キャンセル

  • 2016/03/31 18:46

    補足拝見しました.strtrで Mr. → Mr. を入れておくか,preg_replace で Mr\.(*SKIP)(*FAIL) を入れておけばいけそうですね.

    キャンセル

  • 2016/03/31 18:52 編集

    求められる処理は置換というより分割なので,preg_splitのほうがいいかもしれません.もう1つ高度なテクニックである置換位置のリセット \K も使いますが,これを使って

    $str = 'I am Tom. He is Mr. Smith.';
    $sentences = preg_split('/(?:Mr|Mr?s|Dr|Sir|Prof)\.(*SKIP)(*FAIL)|\.\K\s+/', $str);

    で望んだ通りの結果が得られると思います.

    キャンセル

+2

res = "eeedddffff";
になります。

なりません。
/[^abc]+/ というパターンで "aeeebbdddabccccffff" を検索したら "eee" が引っかかります。

言いたいことはそういうこでではないのでしょうか? "aeeebbdddabccccffff"に対して/[^abc]+/というパターンをどういう風に適用すると"eeedddffff"というテキストが得られるのでしょうか。まずはそこからです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

aeeebbdddabccccffffこの時、正規表現がreg = "/[^abc]+/";
であれば、「a, b, c」以外になるので、res = "eeedddffff";になります。

「aeeebbdddabccccffff」に「reg = "/[^abc]+/";」で検索かけると、HITするのは「eee」と「ddd」と「ffff」だと思いますよ。
regの意味は「a」でも「b」でも「c」でもない文字一文字以上の連続した塊です。

preStr = "aeeebbddd「abc」cccffff";
resStr = "aeeebbdddcccffff";
となる様な正規表現

条件に一致する塊を検出するものですから、間を抜いた文字列を正規表現だけで直接取り出すことは出きません。単にresStrを得たいだけなら「abc」を検出して、これを空白に置換してしまえば良いのではないでしょうか?

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

/abc/ で期待した値が得られると思いますが。間違ってたら、すいません。

  • Code
$pattern='/abc/'; $replacement=''; $string='aeeebbdddabccccffff';
echo preg_replace($pattern, $replacement, $string);
  • result
aeeebbdddcccffff

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/29 23:21

    この方法なら正規表現を使うまでもないので、str_replaceでも実現できますね。
    http://php.net/manual/ja/function.str-replace.php

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • PHP

    20765questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • Java

    14056questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。