何処が間違っているのか教えて下さい。


<pre>
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');

$data = array(
'ほげほげ',
'- 田中 E A C B C E D',
'6 鈴木 C B B B A C D',);

foreach($data as $val){
$pattern="/(^\w\s)(..)(\s)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])/";
$rank='';
if(preg_match($pattern,$val,$match)){
if('$match[$18]' == 'S'){
$rank='6';
}elseif('$match[$18]' == 'A'){
$rank='6';
}elseif('$match[$18]' == 'B'){
$rank='4';
}elseif('$match[$18]' == 'C'){
$rank='3';
}elseif('$match[$18]' == 'D'){
$rank='2';
}elseif('$match[$18]' == 'E'){
$rank='1';
}
}
print $val.$rank."<br>\n";
}
?>
</pre>

エラーは出ないのですが、$valだけが表示され、
$rankの数値が追加されません。
ご教授いただければ幸いです。
宜しくお願い申し上げます。

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2010/03/20 18:34:51
  • 終了:2010/03/22 13:06:22

ベストアンサー

id:tezcello No.7

tezcello回答回数457ベストアンサー獲得回数682010/03/21 00:00:18

ポイント18pt

正規表現がマッチしないのは、. をマルチバイト文字(=漢字)1文字にマッチすると考えて記述しているのが原因では?

UTF-8 で記述し、u 修飾子を指定してはどうでしょう。

http://jp2.php.net/manual/ja/reference.pcre.pattern.modifiers.ph...

明らかな間違い

  • (半角ハイフン)を ¥w でマッチしようとした

' (単引用符)内に展開したい変数を記述した

$18 という変数を使おうとした

を修正すれば、動作すると思いますよ?

でも、例のような2文字の名字だけならOKでしょうけど、1文字とか4文字とかの名字の人は居ないという前提でしょうかね?(よけいなお世話ですが)


挙っていない別の方法を書いてみます。

UTF-8 で記述する事が前提です。

$ptrn = array(
'/^[^A-Z]+?S.+$/u',
'/^[^A-Z]+?A.+$/u',
'/^[^A-Z]+?B.+$/u',
'/^[^A-Z]+?C.+$/u',
'/^[^A-Z]+?D.+$/u',
'/^[^A-Z]+?E.+$/u'
);
$rplc = array(
'${0}6',
'${0}6',
'${0}4',
'${0}3',
'${0}2',
'${0}1'
);

foreach ($data as $val){
print preg_replace($ptrn, $rplc, $val, 1)."<br>\n";
}

最初に現れる S 〜 E の文字で $rank の値が変るようなので、それに対応するパターンと置換する $rank の値をそれぞれ配列に入れてみました。

preg_replace() はパターンにマッチしない場合は元の文字列を返すのを利用しています。


もう一つ別のを。

$ary = array(
'S'=>6,
'A'=>6,
'B'=>4,
'C'=>3,
'D'=>2,
'E'=>1
);
foreach ($data as $val){
$rank = '';
if (preg_match('/^.+?([SABCDE])/u', $val, $mch)){
$rank = $ary[$mch[1]];
}
print $val.$rank."<br>\n";
}

やはり、最初に現れる S〜E の文字に対応する値を連想配列にしておいて、それを正規表現で引っ張りだした値で呼び出しています。

正規表現で引っ張りだすのを、preg_match_all() や、他の方のご提案の preg_split() で取り出すのもアリでしょう。




foreach() ループ内で $pattern をセットすると、ループを回るたびに「同じ値」をセットし直します。

無意味なので、ループの前にセットする方が良いでしょうね。

id:himedaisan

ご丁寧にどうも有難うございました。

大変助かりました。

いくつものパターンをご教授いただいて、

非常に勉強になりました。

2010/03/22 02:28:38

その他の回答(6件)

id:Km1967 No.1

Km1967回答回数224ベストアンサー獲得回数352010/03/20 19:15:50

ポイント17pt

いろいろある。


(1)結果的に、どのような形の出力を求めているのかが書かれていない。

何をすれば正しいのかが伝わってきていない。回答者はエスパーではないぞ。

以下、とりあえず気づいた点だ。


(2)正規表現にマッチしていない

動作確認用の出力を入れてみよ。正規表現が正しく無いことが判るはずだ。

    if(preg_match($pattern, $val, $match)){
        echo "マッチ!";
    } else {
        echo "ノーマッチ!";
    }

以下は一例だ。必要の無い(かっこ)は無駄だから削るほうが良いぞ。

$pattern = "/^.\s.+?\s([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])/";

(3)$18とは何だ?

書くとすれば以下のような形になるはずだ。シングルクォートで囲んでしまうと文字列として認識されてしまうぞ。変数の中身が必要ならシングルクォートで囲む。

        if($match[$18] == 'S'){

どういった結果になれば良いのかが判らないと、こんなところだ。

id:himedaisan

error_reporting(E_ALL);

ini_set('display_errors', '1');

$data = array(

'ほげほげ',

'- 田中 E A C B C E D',

'6 鈴木 C B B B A C D',);

foreach($data as $val){

$pattern="/(^.\s)(..)(\s)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])/";

$rank='';

if(preg_match($pattern,$val,$match)){

if($match[4] == 'S'){

$rank='6';

}elseif($match[4] == 'A'){

$rank='6';

}elseif($match[4] == 'B'){

$rank='4';

}elseif($match[4] == 'C'){

$rank='3';

}elseif($match[4] == 'D'){

$rank='2';

}elseif($match[4] == 'E'){

$rank='1';

}

}

print $val.$rank."
\n";

}

?>

表示結果は$dataだけがそのまま表示されるので、

$patternの4番目がA~Zにマッチした場合には、対応した数値を行末に追加したいのです。

■現状の表示結果

ほげほげ

  • 田中 E A C B C E D

6 鈴木 C B B B A C D

■表示結果希望

ほげほげ

  • 田中 E A C B C E D1

6 鈴木 C B B B A C D3

改めて宜しくお願いいたします。

2010/03/20 20:43:32
id:Bombastus No.2

ホーエンハイム回答回数409ベストアンサー獲得回数522010/03/20 19:20:10

ポイント17pt

どのような処理をしたいのかお知らせください。


まず第一に、下記の正規表現だと、$dataのどの要素にもマッチしません。したがって、if文以下のどれも実行されません。

$pattern="/(^\w\s)(..)(\s)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])/";

次に、たとえマッチしたとしても、'$match[$18]' という表記は間違えで、$match[18] のようにしてください。

id:himedaisan

見難くて申し訳ございません。

以下、再度記載します。

error_reporting(E_ALL);

ini_set('display_errors', '1');

$data = array(

'ほげほげ',

'- 田中 E A C B C E D',

'6 鈴木 C B B B A C D',);

foreach($data as $val){

$pattern="/(^.\s)(..)(\s)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])/";

$rank='';

if(preg_match($pattern,$val,$match)){

if($match[4] == 'S'){

$rank='6';

}elseif($match[4] == 'A'){

$rank='6';

}elseif($match[4] == 'B'){

$rank='4';

}elseif($match[4] == 'C'){

$rank='3';

}elseif($match[4] == 'D'){

$rank='2';

}elseif($match[4] == 'E'){

$rank='1';

}

}

print $val.$rank."
\n";

}

?>

表示結果は$dataだけがそのまま表示されるので、

$patternの4番目がA~Zにマッチした場合には、対応した数値を行末に追加したいのです。

■現状の表示結果

ほげほげ

  • 田中 E A C B C E D

6 鈴木 C B B B A C D

■表示結果希望

ほげほげ

  • 田中 E A C B C E D1

6 鈴木 C B B B A C D3

改めて宜しくお願いいたします。

2010/03/20 20:41:02
id:taknt No.3

きゃづみぃ回答回数13537ベストアンサー獲得回数11982010/03/20 20:19:28

ポイント17pt

質問の仕方が 間違ってます。

どういうことを やりたいのか まず仕様を説明し、それから現在 どのようなプログラムなのかソースを提示し、問題となっていることを 出すべきです。

それさえ 提示できれば、希望の回答がくる確率が高くなります。

id:himedaisan

申し訳ございません。

記載内容に誤りがありました。

error_reporting(E_ALL);

ini_set('display_errors', '1');

$data = array(

'ほげほげ',

'- 田中 E A C B C E D',

'6 鈴木 C B B B A C D',);

foreach($data as $val){

$pattern="/(^.\s)(..)(\s)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])(\s+)([A-Z])/";

$rank='';

if(preg_match($pattern,$val,$match)){

if($match[4] == 'S'){

$rank='6';

}elseif($match[4] == 'A'){

$rank='6';

}elseif($match[4] == 'B'){

$rank='4';

}elseif($match[4] == 'C'){

$rank='3';

}elseif($match[4] == 'D'){

$rank='2';

}elseif($match[4] == 'E'){

$rank='1';

}

}

print $val.$rank."
\n";

}

?>

表示結果は$dataだけがそのまま表示されるので、

$patternの4番目がA~Zにマッチした場合には、対応した数値を行末に追加したいのです。

■現状の表示結果

ほげほげ

  • 田中 E A C B C E D

6 鈴木 C B B B A C D

■表示結果希望

ほげほげ

  • 田中 E A C B C E D1

6 鈴木 C B B B A C D3

改めて宜しくお願いいたします。

2010/03/20 20:34:28
id:Km1967 No.4

Km1967回答回数224ベストアンサー獲得回数352010/03/20 20:52:20

ポイント17pt

正規表現は動かぬから書き直した。それにあわせてifも書き直してある。

Aのときは6ではなく5であろうから勝手に直した。確認用のechoは後からはずせばいい。

<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');

$data = array(
'ほげほげ',
'- 田中 E A C B C E D',
'6 鈴木 C B B B A C D',);

foreach($data as $val){
    $pattern = "/^.\s.+?\s([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])/";
    $rank='';
    if(preg_match($pattern, $val, $match)){
        echo "マッチ!";
        if($match[1] == 'S'){
            $rank = '6';
        }elseif($match[1] == 'A'){
            $rank = '5';
        }elseif($match[1] == 'B'){
            $rank = '4';
        }elseif($match[1] == 'C'){
            $rank = '3';
        }elseif($match[1] == 'D'){
            $rank = '2';
        }elseif($match[1] == 'E'){
            $rank = '1';
        }
    } else {
        echo "ノーマッチ!";
    }
    echo $val . $rank . "<br>\n";
}
?>

結果出力(田中は E だから 1、鈴木は C だから 3)

ノーマッチ!ほげほげ<br>
マッチ!- 田中 E A C B C E D1<br>
マッチ!6 鈴木 C B B B A C D3<br>

コードの読みやすさを考えれば if を並べるより switch のほうがスマートだろう。

一度にやると頭が混乱するだろうから 今は、下のURLだけ控えておけばいい。時間と気持ちの余裕が出来たら読んでみよ。

http://php.net/manual/ja/control-structures.switch.php

id:himedaisan

ご丁寧にどうも有難うございました。

大変助かりました。

2010/03/22 02:27:33
id:Bombastus No.5

ホーエンハイム回答回数409ベストアンサー獲得回数522010/03/20 21:26:32

ポイント17pt

preg_matchを使っているのがよろしくないと存じます。

勝手ながら、preg_matchをpreg_splitに変更し、if-elseif文をcase文に変更させていただきました。

また、これが正しい結果を示すのは、内部エンコーディングがutf-8の場合です。ご留意ください。

<pre>
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');

$data = array(
'ほげほげ',
'- 田中 E A C B C E D',
'6 鈴木 C B B B A C D'
);

foreach ($data as $val){
    $rank='';
    $match = preg_split('/[ ]+/u', $val);
    if (isset($match[2])) {
        switch ($match[2]) {
            case 'S':   $rank = '6';    break;
            case 'A':   $rank = '6';    break;
            case 'B':   $rank = '4';    break;
            case 'C':   $rank = '3';    break;
            case 'D':   $rank = '2';    break;
            case 'E':   $rank = '1';    break;
        }
    }
    print $val . $rank . "<br>\n";
}
?>
</pre>
id:himedaisan

ご丁寧にどうも有難うございました。

大変助かりました。

2010/03/22 02:27:50
id:Km1967 No.6

Km1967回答回数224ベストアンサー獲得回数352010/03/20 23:29:19

ポイント17pt

splitは単純に切り分けるだけで、構造チェックが入っていないから気をつけないといけないぞ。

switchの例が出ていたので、もうちょっと違う方向からやってみても面白かろう。 完全に雑談になるが、今後、チューニングや軽量化を考えていく時の礎となろうぞ。

パターンは末尾に$をつけて厳密度をあげてある。

foreach($data as $val){
    $pattern = "/^.\s.+?\s([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])\s+([A-Z])$/";
    $rank = '';
    if(preg_match($pattern, $val, $match)){
        $rank = strpos(' EDCBAS', $match[1]);
    }
    echo $val . $rank . "<br>\n";
}
id:himedaisan

ご丁寧にどうも有難うございました。

大変助かりました。

2010/03/22 02:28:00
id:tezcello No.7

tezcello回答回数457ベストアンサー獲得回数682010/03/21 00:00:18ここでベストアンサー

ポイント18pt

正規表現がマッチしないのは、. をマルチバイト文字(=漢字)1文字にマッチすると考えて記述しているのが原因では?

UTF-8 で記述し、u 修飾子を指定してはどうでしょう。

http://jp2.php.net/manual/ja/reference.pcre.pattern.modifiers.ph...

明らかな間違い

  • (半角ハイフン)を ¥w でマッチしようとした

' (単引用符)内に展開したい変数を記述した

$18 という変数を使おうとした

を修正すれば、動作すると思いますよ?

でも、例のような2文字の名字だけならOKでしょうけど、1文字とか4文字とかの名字の人は居ないという前提でしょうかね?(よけいなお世話ですが)


挙っていない別の方法を書いてみます。

UTF-8 で記述する事が前提です。

$ptrn = array(
'/^[^A-Z]+?S.+$/u',
'/^[^A-Z]+?A.+$/u',
'/^[^A-Z]+?B.+$/u',
'/^[^A-Z]+?C.+$/u',
'/^[^A-Z]+?D.+$/u',
'/^[^A-Z]+?E.+$/u'
);
$rplc = array(
'${0}6',
'${0}6',
'${0}4',
'${0}3',
'${0}2',
'${0}1'
);

foreach ($data as $val){
print preg_replace($ptrn, $rplc, $val, 1)."<br>\n";
}

最初に現れる S 〜 E の文字で $rank の値が変るようなので、それに対応するパターンと置換する $rank の値をそれぞれ配列に入れてみました。

preg_replace() はパターンにマッチしない場合は元の文字列を返すのを利用しています。


もう一つ別のを。

$ary = array(
'S'=>6,
'A'=>6,
'B'=>4,
'C'=>3,
'D'=>2,
'E'=>1
);
foreach ($data as $val){
$rank = '';
if (preg_match('/^.+?([SABCDE])/u', $val, $mch)){
$rank = $ary[$mch[1]];
}
print $val.$rank."<br>\n";
}

やはり、最初に現れる S〜E の文字に対応する値を連想配列にしておいて、それを正規表現で引っ張りだした値で呼び出しています。

正規表現で引っ張りだすのを、preg_match_all() や、他の方のご提案の preg_split() で取り出すのもアリでしょう。




foreach() ループ内で $pattern をセットすると、ループを回るたびに「同じ値」をセットし直します。

無意味なので、ループの前にセットする方が良いでしょうね。

id:himedaisan

ご丁寧にどうも有難うございました。

大変助かりました。

いくつものパターンをご教授いただいて、

非常に勉強になりました。

2010/03/22 02:28:38

コメントはまだありません

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

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

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

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