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

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

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

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

Q&A

解決済

1回答

4011閲覧

PHP5から7にしたらParse error: Invalid numeric literalが出たので強引に対応したけどもっと良い方法はないでしょうか?

PenelopeG

総合スコア31

PHP

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

0グッド

0クリップ

投稿2020/05/21 15:59

只今、独学でプログラミング勉強中です。
「プログラマ脳を鍛える数学パズル」という本を始めましたが2問目で悩んでいます。
本にはPHPでの回答は載っていないのでご教授いただきたいです。

問題は、
1000〜9999のうち、数字の各桁の間に四則演算の演算子を入れて計算し、その計算結果が元の数の桁を逆から並べた数字と同じになるものを考えます。(演算子を入れない場所があってもOK。ただし最低でも1つは入れる)

数字の各桁の間に四則演算の演算子を入れる例:
1234 → 1+23-4 = 3
9876 → 9
87+6 = 789

100〜999の場合:
351 → 351 = 153
621 → 6
21 = 126
886 → 8*86 = 688

この問題をPHPでやってみました。

PHP

1// 演算子を配列に格納(※条件に必要となる演算子は「*」のみ) 2$op = array('*', ''); 3 4for ($num = 1000; $num <= 9999; $num++) { 5 // 数値を1文字ずつ分解して配列に格納 6 $num_arr = str_split($num); 7 8 for ($i = 0; $i < count($op); $i++) { 9 for ($j = 0; $j < count($op); $j++) { 10 for ($k = 0; $k < count($op); $k++) { 11 // 式を文字列で生成 12 $temp = $num_arr[0] . $op[$i] . $num_arr[1] . $op[$j] . $num_arr[2] . $op[$k] . $num_arr[3]; 13 // 文字列式を計算 14 $calc_res = eval("return {$temp};"); 15 16 if (mb_strlen($temp) >= 5 && strrev($num) == $calc_res) { // 演算子は最低でも1つは入れる=5桁以上 17 print $num . "\n"; 18 } 19 } 20 } 21 } 22}

PHP5では上記で動いていたのですが、これをPHP7で実行すると以下のようなエラーが出ました。

Parse error: Invalid numeric literal in (ファイル名): eval()'d code on line 1

文字列式に「00」など先頭が0で始まる数字が含まれてしまうことでエラーが出ているのだろうと思い、以下のようにしてみたところ、一応うまく動きました。

PHP

1// 演算子を配列に格納(※条件に必要となる演算子は「*」のみ) 2$op = array('*', ''); 3 4for ($num = 1000; $num <= 9999; $num++) { 5 // 数値を1文字ずつ分解して配列に格納 6 $num_arr = str_split($num); 7 8 for ($i = 0; $i < count($op); $i++) { 9 for ($j = 0; $j < count($op); $j++) { 10 for ($k = 0; $k < count($op); $k++) { 11 // 式を文字列で生成 12 $temp = $num_arr[0]. $op[$i]. $num_arr[1]. $op[$j]. $num_arr[2]. $op[$k]. $num_arr[3]; 13 14 // 生成された式を演算子で分解し、先頭が0の数字は0を除外する 15 $re_temp = ''; 16 $temp = explode('*', $temp); 17 foreach ($temp as $val) { 18 if ($val != '*') { 19 $val = intval($val); 20 } 21 $re_temp .= $val. '*'; 22 } 23 $re_temp = substr($re_temp, 0, -1); 24 25 // 文字列式を計算 26 $calc_res = eval("return {$re_temp};"); 27 28 if (mb_strlen($re_temp) >= 5 && strrev($num) == $calc_res) { // 演算子は最低でも1つは入れる=5桁以上 29 print $num . "\n"; 30 } 31 32 } 33 } 34 } 35}

答えは正しく出たのですが、必要になる演算子が「*」のみというのが前提のかなり強引な方法です。
もっと良い方法があれば教えていただきたいです。

ちなみに、eval関数を使用するのは避けて逆ポーランド記法などを使って実装すべきかもしれませんが、ここではそれはまた別の話とさせてください。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

PHP5では上記で動いていたのですが、これをPHP7で実行すると以下のようなエラーが出ました。

php 5 系でもまともに動いていません。
今回のエラーは

php

1return 1*0*08

が最初に引っかかってます。
0 を頭に付ける表記は 8進数を表します。

5 系では、8進数として正しくない表現は無視(?)されていましたが、
7 系では、8進数として正しくない表現はエラーとすることになりました。

計算としても、8進数で計算されています。

php

1echo 1 * 017; 2//15

もともと正しく動いていなかったコードが、正しく(?)エラーを吐くようになっただけです。

マニュアルの該当箇所は以下です。
構文-整数 php.net
Invalid octal literals

正常に動かすには、すでに検討しているように
・文字列から、頭に 0 のついた数字を 0 なしのものに置換
する必要があります。

正規表現でも使用すると適切に対応できると思います。

投稿2020/05/21 23:15

編集2020/05/22 02:45
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PenelopeG

2020/05/22 02:28

なるほど。5系でもまともに動いてなかったのですね。勉強になりました。 「正規表現を使って先頭が0のついた数字を0なしに置換」の方がスマートですね。 やってみます。ありがとうございます。
退会済みユーザー

退会済みユーザー

2020/05/22 02:51 編集

少し文章の構成を変えました。 *内容は変わっていません。 回答には正規表現が適切と書きましたが、最適は他にあるような気がします。 文字連結の箇所を数字+(演算子)を返す関数化して、演算子を含まないときの 0 始まりを除外するのがプログラム的には正しいと思います。 時間があれば、チャレンジしてみてください。
PenelopeG

2020/05/25 08:07

関数化した方がすっきりしそうですね。やってみます。ご丁寧にありがとうございました。
退会済みユーザー

退会済みユーザー

2020/05/25 08:16

関数化は、「スッキリする」というよりは、「より設計意図を反映したコード」になると思いますが、そもそも設計が結構めんどくさいです。 イメージできたら先に進んじゃっても良い気がします。
PenelopeG

2020/05/25 23:21

おっしゃるとおりです。関数化にチャレンジしましたがスッキリするコードになりそうにありません。それでも「より設計意図を反映したコード」になるので後から見たときにわかりやすいのだと理解しました。 「イメージできたら先に進んじゃっても良い気がします。」という言葉に救われました。あまり固執せずに進めていこうと思います。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問