PerlもしくはPHPの正規表現で


キーワード「あいうえお」を入力したとき
長い文字列のなかから、
「あいxえお」
「あいうえe」
「あ●うえお」
など
このように1文字違っていても
抽出するようにしたいんですが可能でしょうか?
可能であればソースプログラムを教えて下さい。

回答の条件
  • URL必須
  • 1人2回まで
  • 登録:2007/09/10 23:14:59
  • 終了:2007/09/17 14:09:23

ベストアンサー

id:GEN111 No.1

GEN111回答回数472ベストアンサー獲得回数582007/09/11 00:45:35

ポイント28pt

PHPで。

もっとイカしたやり方がありそうな気もしますが。

function nealy_match($pat, $target) {
  $pchars = preg_split('/(?<!^)(?!$)/u', $pat) ;
  $newpat = array() ;
  for ($i = 0, $tmp = array(); $i < count($pchars); ++$i) {
    $tmp = $pchars ;
    $tmp[$i] = '.' ;
    $newpat[] = implode('', $tmp) ; 
  }
  preg_match_all('/('.implode('|', $newpat).')/u', $target, $matches) ;
  return $matches[0] ;
}

$str = '吾輩は猫である。あいxえお。名前はまだ無い。あいうえe。どこで生れたかとんとあ●うえおがつかぬ。';
$pat = 'あいうえお' ;

print_r(nealy_match($pat, $str)) ;

PHP: preg_match_all - Manual

id:tembin11

動きました。

素晴らしいですね。有難うございます。

2007/09/11 01:35:58

その他の回答(2件)

id:GEN111 No.1

GEN111回答回数472ベストアンサー獲得回数582007/09/11 00:45:35ここでベストアンサー

ポイント28pt

PHPで。

もっとイカしたやり方がありそうな気もしますが。

function nealy_match($pat, $target) {
  $pchars = preg_split('/(?<!^)(?!$)/u', $pat) ;
  $newpat = array() ;
  for ($i = 0, $tmp = array(); $i < count($pchars); ++$i) {
    $tmp = $pchars ;
    $tmp[$i] = '.' ;
    $newpat[] = implode('', $tmp) ; 
  }
  preg_match_all('/('.implode('|', $newpat).')/u', $target, $matches) ;
  return $matches[0] ;
}

$str = '吾輩は猫である。あいxえお。名前はまだ無い。あいうえe。どこで生れたかとんとあ●うえおがつかぬ。';
$pat = 'あいうえお' ;

print_r(nealy_match($pat, $str)) ;

PHP: preg_match_all - Manual

id:tembin11

動きました。

素晴らしいですね。有難うございます。

2007/09/11 01:35:58
id:tezcello No.2

tezcello回答回数459ベストアンサー獲得回数692007/09/11 01:30:03

ポイント27pt

泥臭い方法ですけど、1文字違いなら全部書いてしまった方が単純でしょう。

キーワードの1文字づつをピリオドにかえてパイプで連結します。

最後のパイプは不要なので、削除し、全体をかっこで閉じて、検索文字列を作ります。(記述している順序は違いますが)

後はmb_ereg() で検索します。

http://www.php.net/manual/ja/function.mb-ereg.php

$ary = array(
    'い○●にあいxえおながいもじれつ'
  ,'長い文字列あいうえeろはにほへと'
  ,'もじもじもじあ●うえおいrはに'
  ,'いろはおあいUEおもじもじ'
  );
  $key = 'あいうえお';
  $length = mb_strlen($key);
  $pattern = '(';
  for ($i=0; $i<$length; $i++){
    $chr = '/'.mb_substr($key, $i, 1).'/';
    $pattern .= preg_replace($chr, '.', $key).'|';
  }
  $pattern =preg_replace('/\.\|/', '.)', $pattern);
  foreach($ary as $str){
    $res = mb_ereg($pattern, $str);
    if ($res) print "$str is match!<br>\n";
  }
id:tembin11

有難うございます。

OKかNGかならこちらのほうが処理速度が

早いですね

2007/09/11 22:02:51
id:b-wind No.3

b-wind回答回数3344ベストアンサー獲得回数4402007/09/11 10:14:38

ポイント25pt

perl で文字コードは sjis に。

#!/usr/bin/perl

use encoding sjis;

my $regex = '(?:(あ)|.)(?:(い)|.)(?:(う)|.)(?:(え)|.)(?:(お)|.)';
my @str = qw/
  あいxえお
  あいうえe
  あ●うえお
  あかさたな
 /;
foreach my $str ( @str ) {
   my @match = $str =~ m/$regex/;
   my @count = grep { defined $_ } @match;
   printf "string: %s is %s\n" , $str, @count >= 4 ? "match" : "unmatch";
}

Perl の演算子と優先順位


まぁまぁかな。

  • id:GEN111
    UTF-8で、と但し書きを入れるつもりが忘れてました。
    ちゃんと動いたようで何よりです。
  • id:tezcello
    質問を理解出来ていなかった様ですね、ごめんなさい。
    抽出するのなら、最初の方の様に、preg_match_all() が簡単でいいですね。
    同様にUTF-8である事が必要です。いつもは以下の様な決まり文句を使ってます。
    set_magic_quotes_runtime(false);
    ini_set('mbstring.http_input', 'pass');
    ini_set('mbstring.http_output', 'pass');
    mb_language('ja');
    mb_internal_encoding('UTF-8');
    mb_regex_encoding('UTF-8');

    で、preg_match_all() 用に書き直したのはこれ。
    $ary = array(
    'い○●にあいxえおながいもじれつあいうえお'
    ,'長い文字列あいうえeろはにほへと'
    ,'もじもじもじあ●うえおいrはに'
    ,'いろはおあいUEおもじもじ'
    );
    $key = 'あいうえお';

    $length = mb_strlen($key);
    $pattern = '/(';
    for ($i=0; $i<$length; $i++){
    $chr = '/'.mb_substr($key, $i, 1).'/';
    $pattern .= preg_replace($chr, '.', $key).'|';
    }
    $pattern =preg_replace('/\.\|/', '.)/u', $pattern);

    foreach($ary as $str){
    $res = preg_match_all($pattern, $str, $result);
    if ($res) var_dump($result[0]);
    }
  • id:GEN111
    ちょこっと改良。
    ほんのちょこっと速くなりました。
    function nearly_match($pat, $target) {
    $plen = count(preg_split('//u', $pat))-2 ;
    for ($i=0; $i < $plen; ++$i)
    $newpat[] = preg_replace('/(.{'.$i.'}).(.*)/u', '$1.$2', $pat) ;
    preg_match_all('/('.implode('|',$newpat).')/u', $target,$matches) ;
    return $matches[0] ;
    }
    関数名 typo してました。 nearly_match です。恥ずかしい。


    tezcello さんの
    >>
    $chr = '/'.mb_substr($key, $i, 1).'/';
    $pattern .= preg_replace($chr, '.', $key).'|';
    <<
    この部分は「あいうえあ」みたいに同じ文字がある場合にまずくないですか?
  • id:tezcello
    その通りですね、ご指摘感謝です。>GEN111さん
    「あいうえお」に釣られてしまってますね。
    検索文字列を作る方法で、
    ・1文字づつに分解して、接合する
    ・N文字目以前と以後とに分け、接合する
    ・N文字目をピリオドに置き換える
    と考えて来て、N文字目に注目してた筈なのにN文字目の文字で検索掛けてしまいました。
    mb_substr() 使ってるのだから、チャンと出来た筈なのに...ツメが甘いです。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません