MiracleJobLogo
エンジニアのエンジニアによるエンジニアのためのサイト
News 07/19 おすすめ情報に 『 【資格取得者速報】 Aさん 「 Microsoft Security, Compliance, and Identity Fundamentals」 』 を追加しました。
会員登録するとキャリア診断やサイトに参加することができます。
あなたにおすすめな技術情報、資格、仕事などをお知らせします。

無料会員登録


パスワードを忘れた場合
LINEで送る
MiracleJobBanaLeft1
MiracleJobBanaLeft2


3の倍数と3がつく数字でアホになるPowerShellスクリプト
profile-img
投稿者: muto-sanさん
投稿日:2018/10/03 21:25
更新日:2018/10/03 21:42
like-img
分類
技術
テクノロジー
全般
キャリア
テクニカルサポート
投稿内容

30歳過ぎてようやくプログラミング能力の必要性に気付いてスクリプティングを勉強中のTMutohです。

Infrastrucrure as Codeなんて言葉もあるくらいだしインフラ屋だからって全くできないのはマズいよね。


てことで、練習として大昔に流行ったアレをスクリプト化するってのをやってみました。

基本はFizzBuzzなので入門的なものとしてちょうどいいですね。

※ FizzBuzzってなに?って人はこちら

まず単一の数字に対しての処理を整理してみます。

入力
 aという整数が与えられる。

処理
 aが3の倍数かどうかを判定する。(四則演算・倍数判定)
 aに"3"が含まれているかを判定する。(文字列の検索・繰り返し処理)
 上記の何れかもしくは両方を満たす場合といずれも満たさない場合で出力を分岐。(論理和)

出力
 ここでは下記の二種類しようと思います。
 アホである場合:"(*゚σ▽゚)σ < (数字)!!"
 アホではない場合:"(^o^) < (数字)!"

まずは1つ目の処理[aが3の倍数かどうかを判定する。]を書いてみます。
=====================
# 整数 a が3の倍数である場合フラグを立てる
if ($a % 3 -eq 0){
    $aho = $True
}
=====================
※ %は割り算の余りを求める(剰余)式です。
ifステートメントを使わず[$a % 3 -eq 0]だけでもTrue/Falseが取れますが、後続処理の都合上変数$ahoにフラグを立てています。

2つ目の処理[aに3が含まれているかどうかを判定する。]を書いてみます。
=====================
# 整数 a に3が含まれる場合フラグを立てる
for ($i=0; $i -lt $a.ToString().Length; $i++){
    if ($a.ToString()[$i] -eq "3"){
        $aho = $True
    }
}
=====================

forステートメントを用いて、aのi文字目($a[$i])を判定する処理を桁数分処理しています。
aを文字列型として読ませるためにToStringを用いています。

3つめの処理、「何れかもしくは両方を満たす場合といずれも満たさない場合でそれぞれに合わせた形式で出力」
=====================
# フラグチェック
if ($aho -eq $True){
    # アホパターンの形式で出力
    Write-Output ("(*゚σ▽゚)σ < " + $a + "!!")
}else{
    # 通常パターンの形式で出力
    Write-Output ("(^o^) < " + $a + "!")
}
=====================
以上の組み合わせで、[整数aが3の倍数であるか、3を含む数字である場合アホになる]が出来上がります。

ひとまとめにします。
=====================
# 整数 a が3の倍数である場合フラグを立てる
if ($a % 3 -eq 0) {
    $aho = $True
}
# 整数 a に3が含まれる場合フラグを立てる
for ($i=0; $i -lt $a.ToString().Length; $i++){
    if ($a.ToString()[$i] -eq "3"){
        $aho = $True
    }
}
# フラグチェック
if ($aho -eq $True){
# アホパターンの形式で出力
    Write-Output ("(*゚σ▽゚)σ < " + $a + "!!")
}else{
# 通常パターンの形式で出力
    Write-Output ("(^o^) < " + $a + "!")
}
=====================

単一の数字に対して処理するものが書けたので、あとはこれを指定した回数分処理するようにForEach-Objectで回します。

また、最終値をEndオプションとして指定出来るようにしておきます。
====<nabeatsu.ps1>====
param(
    [int]$End
)

1..$End |ForEach-Object {
    # フラグを初期化
    $aho = $Null
    # 3の倍数判定
    if ($_ % 3 -eq 0) {
        $aho = $True
    }
    # 3を含む判定
    for ($i=0; $i -lt $_.ToString().Length; $i++){
        if ($_.ToString()[$i] -eq "3"){
            $aho = $True
        }
    }
    # フラグチェック
    if ($aho -eq $True){
        # アホパターンの形式で出力
        Write-Output ("(*゚σ▽゚)σ < " + $_ + "!!")
    }else{
        # 通常パターンの形式で出力
        Write-Output ("(^o^) < " + $_ + "!")
    }
}
====<nabeatsu.ps1>====
このスクリプトをオプション付きで実行することで、1から指定した値までの数字が3の倍数か3を含む数字ではアホになった状態で出力されます。


・補足
like演算子とor演算子を使うことでよりPowerShellっぽく簡潔になります。
====<nabeatsu2.ps1>====
param(
    [int]$End
)

1..$End |ForEach-Object {
    if (($_ % 3 -eq 0) -or ($_ -like "*3*")){
        Write-Output ("(*゚σ▽゚)σ < " + $_ + "!!")
    }else{
        Write-Output ("(^o^) < " + $_ + "!")
    }
}
====<nabeatsu2.ps1>====
int型かString型かを意識せずにまとめて処理できるあたりがそれっぽいですね。

・オマケ
並行して勉強中のPython3でも同じものを書いてみました。
====<nabeatsu.py>====
import sys
args = sys.argv
end = int(args[1])
for a in range(1, end+1):
    aho = ''
    if a % 3 == 0:
        aho = True
    for b in range(0, len(str(a))):
        if str(a)[b] == "3":
            aho = True
    if aho == True:
        print("(*゚σ▽゚)σ < {0}!!".format(a))
    else:
        print("(^o^) < {0}!".format(a))

====<nabeatsu.py>====


踊る阿呆に見る阿呆、同じ阿呆ならうんぬんかんぬん。

もっといいやり方があるとか、間違いなどあればどんどん指摘ください。


コメント


profile-img matsuzakiさん
2018/10/08 22:12
と、同じことをやる場合でも処理の書き方はいろいろあります。
じゃあどれが正しいの?という点ですが、
画一的な正解はありません。

処理を実施する端末のスペックや整数aに入るであろう値(桁数など)によって
それぞれ処理速度も変わってきますし
運用の中でスクリプトのメンテナンスがちょいちょい入るのであれば
メンテナンスする人に分かりやすい処理内容の方がよい、などということもあります。

案件の中でスクリプトを作って納品する、という場合は
この辺りのお客様ヒヤリングや実際に動作させる環境での性能試験などを実施し、
最良のものを作っていく、ということが必要になります。

エンジニアの醍醐味ですね。
profile-img matsuzakiさん
2018/10/08 22:06
他にはこんなやり方も。


if ($_.ToString().Contains("3") -eq "True"){
$aho = $True
}


Containsは先ほどのIndexOfよりもっとシンプルで整数aの中から()内の文字を検索し、
あれば"True"を、なければ"False"を返します。
これもTrue/Falseが取れていますが、後続処理のために変数$ahoにフラグを立てています。
profile-img matsuzakiさん
2018/10/08 22:05
>aに"3"が含まれているかを判定する。

のやり方ですが、こんな方法もありますね。


if ($_.ToString().IndexOf("3") -ne -1){
$aho = $True
}


IndexOfは整数aの中から()内の文字を検索し、
最初に見つかった位置(何文字目にあるか)を返すものです。
(最初の1文字目は"0"、2文字目は"1"、3文字目は"2"、という返し方をします。)
また、見つからなかった場合は"-1"を返します。

例)"34"を検索:"0"を返す
  "2334"を検索:"1"を返す
  "10000"を検索:"-1"を返す
これを利用し、返された値が"-1"ではない場合、
変数$ahoに$Trueのフラグを立てています。
MiracleJobBanaRight1
MiracleJobBanaRight2
MiracleJobBanaRight3