全知全能を目指す人のありがたい雑記

何かしら意味のあるありがた~い話か、意味のない雑念だらけの日記を書く予定です。

日付と曜日を表示するプログラム

javaでは一般的にカレンダークラスを使う。

今日からX日後の日付と曜日を出してほしいとのことなので
以下のコードを書いた

import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        Scanner s = new Scanner(System.in);
        int dayDelay = s.hasNext() ? s.nextInt() : 0;
        String[] week = {"日","月","火","水","木","金","土"};
        Calendar now = Calendar.getInstance(); 
        now.add(Calendar.DATE, dayDelay);
        System.out.println(now.get(now.YEAR)+"/"+(now.get(now.MONTH) + 1)+"/"+now.get(now.DATE)+"/" + week[now.get(now.DAY_OF_WEEK) -1]);
    }
}

入力

1

出力

2018/10/6/土

ハードコーディング恐怖症を患いました

ハードコーディング怖い

↓ハードコーディングしてるコード

import java.util.*;

public class Main {
    
    public static void main(String[] args) throws Exception {
        Scanner s = new Scanner(System.in);
        
        //ログインステータスは1が成功でぇ~、0が入力ミスでぇ~、-1がシステムエラーだよ!
        int loginStatus = login(s.nextLine());
        
        switch(loginStatus){
            case 1:
                System.out.println("ログイン成功");
                break;
            case 0:
                System.out.println("ユーザー名を正しく入力してください(8文字以上)");
                break;
            case -1:
                System.out.println("致命的なエラー(適当)");
                break;
        }
    }
    
    public static int login(String password){
        if(password.length() >= 8){
            return 1;
        }else if(password!= null){
            return 0;
        }
        return -1;
    }
    
}

enum使ってくれた女神のようなコード

import java.util.*;

public class Main {
    public enum loginStatus{
        Success,
        InvalidError,
        SystemError,
    }
    
    public static void main(String[] args) throws Exception {
        Scanner s = new Scanner(System.in);
        loginStatus ret = login(s.nextLine());
        
        switch(ret){
            case Success:
                System.out.println("ログイン成功");
                break;
            case InvalidError:
                System.out.println("ユーザー名を正しく入力してください(8文字以上)");
                break;
            case SystemError:
                System.out.println("致命的なエラー(適当)");
                break;
        }
    }
    
    public static loginStatus login(String password){
        if(password.length() >= 8){
            return loginStatus.Success;
        }else if(password!= null){
            return loginStatus.InvalidError;
        }
        
        return loginStatus.SystemError;
    }
    
}

サンプルだからログイン状態を3種類にとどめたけど、
これが10種類もあったら何の値かわからんこっちゃになっちゃうよ・・・。

頼む。みんな気を付けてくれ。
俺の目の前でハードコーディングを絶対にしないでくれ

追記:loginの文字数もハードコーディングだから、サーバー側のコンフィグかどこかにpasswordの最低文字数が決められると良いね。

プログラミングの質問(と回答)はこうあるべき

detail.chiebukuro.yahoo.co.jp

 

こういう質問があった。

 

最初はまったく内容が分からなかったんだけど、

きちんとご説明されていたし、

知識の照らし合わせが互いに出来たと感じた。

 

この切磋琢磨してる感じが良かった。

回答していて楽しいと感じられた。

 

課題を丸投げするな質問者さんより、

こういう質問者さんが増えると良いなぁ~。

 

良質な質問者でした。

 

おやすみなさい。

 

2019/01/17 追記:

単に自分が「トークン」の意味を知らないだけだった。無知は恥ずかしい。

e-words.jp

調べればちゃんと意味が書いてあるやん!

「プログラミングでは、ソースコードを解析する際にそれ以上細かい単位に分解できない文字列の並びの最小単位(要素名や演算子など)のこと」

 

トークンみたいな抽象的な言葉って、ついついその言葉の1部分だけを知ってるだけで分かった気になっちゃうけど、とても良くない考え方だね。

 

オブジェクト指向について語ってる記事がよく炎上する理由も分かる。

配列を使用して入力した数字から最大値・最小値・平均値を求めるプログラム

入力が一定ではないならリストの方が良いんだけどなぁ…
っていうのは学生の課題だから仕方ない?

とりあえず、配列の要素数は5にしています。
いつも通り、機能要件を満たす最低限のコードしか書いてません。

import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        Scanner s = new Scanner(System.in);
        int[] array = new int[5];
        int min = Integer.MAX_VALUE;
        int max = 0;
        int sum = 0;
        
        for(int element: array){
            element = s.nextInt();
            min = Math.min(min,element);
            max = Math.max(max,element);
            sum += element;
        }
        
        System.out.printf("Min=%d\n",min);
        System.out.printf("Max=%d\n",max);
        System.out.printf("Ave=%f\n",(float)sum/array.length);
    }
}

入力

3 6 7 9 12

出力

Min=3
Max=12
Ave=7.400000

.NETを使って「時間差」と「指定した時間が指定した時間帯か」を求めるプログラム

人のソース引用してます
C#で特定の時間帯に含まれるか判定
時間を表すTimeSpanオブジェクトを作成する、情報を取得する - .NET Tips (VB.NET,C#...)

using System;

public class HowToUseDateTime{
    public static void Main(){
        DateTime a = new DateTime(2018, 9, 28, 10, 05, 0);
        DateTime b = new DateTime(2018, 9, 28, 15, 10, 0);
        
        if(InRange(a,1000,1015)){
           Console.WriteLine("aのインスタンスは正しい時間帯");
        }
        else
        {
           Console.WriteLine("aのインスタンスは正しくない時間帯");
        }
        
        TimeSpan ts = a - b;
        
        Console.WriteLine("時間差は{0}です。",ts.ToString("c"));
    }
    
    public static bool InRange(DateTime dt, int from, int to){
        string stringhhmm = dt.ToString("HHmm");
        int inthhmm = Int16.Parse(stringhhmm);
        return inthhmm >= from && inthhmm <= to;
    }
}

出力

aのインスタンスは正しい時間帯
時間差は-05:05:00です。

多次元配列を使って遊ぶプログラム

以下のような模様を出力してほしいらしい。

■□■□■□■□■□■
□□■□■□■□■□■
■■■□■□■□■□■
□□□□■□■□■□■
■■■■■□■□■□■
□□□□□□■□■□■
■■■■■■■□■□■
□□□□□□□□■□■
■■■■■■■■■□■
□□□□□□□□□□■
■■■■■■■■■■■

コード

import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        
        final int size = 11;
        boolean[][] drawFlags = new boolean[size][size];
        
        for(int line = 0; line < size; ++line){
            if(line%2==0){
                for(int anotherLine = 0; anotherLine <= line; ++anotherLine){
                    drawFlags[line][anotherLine] = true;
                    drawFlags[anotherLine][line] = true;
                }
            }
        }
        
        for(int row = 0; row < size; ++row){
            for(int colomn = 0; colomn < size; ++colomn){
                String mark = drawFlags[colomn][row] ? "■" : "□";
                System.out.print(mark);
            }
            System.out.println();
        }
    }
}

出力

■□■□■□■□■□■
□□■□■□■□■□■
■■■□■□■□■□■
□□□□■□■□■□■
■■■■■□■□■□■
□□□□□□■□■□■
■■■■■■■□■□■
□□□□□□□□■□■
■■■■■■■■■□■
□□□□□□□□□□■
■■■■■■■■■■■

sizeを変えると描画数も変わるように作った。

文字列1から文字列2を検索するプログラム+解説

strstrっていう関数がある

#include <string.h>
char *strstr(const char *s1, const char *s2);

これを学習目的で自作する人が居たので、類似のソースを見つけて解説してみた
printfで出力の途中経過を混ぜてます

ソース

#include <stdio.h>

char *myStrstr(const char *s1, const char *s2)
{
    printf("start\n");
    const char *p1 = s1;
    const char *p2 = s2;
    
    while (*p1 && *p2) {
        if (*p1 == *p2) {
            p1++;
            p2++;
            printf("true [p1:%s] [p2:%s]\n",p1,p2);
        } else {
            long diff = (p2-s2-1);
            p1 -= p2 - s2 - 1;
            p2 = s2;
            printf("false [p1:%s] [p2:%s] ",p1,p2);
            printf("p1 pointer moves %ld\n",diff);
        }
    }
    printf("end\n");
    printf("p2 is [%s], [%s] - ([%s] - [%s]) = [%s]\n",p2,p1,p2,s2,(p1 - (p2 - s2)));
    return (*p2 ? NULL : (char *)(p1 - (p2 - s2)));
}

int main(void){
    const char* str1 = "eyanyaoewar9nyan349reawr";
    const char* str2 = "nyan";
    
    char* str3 = myStrstr(str1,str2);
    
    printf("result is %s",str3); 
}

str1を「eyanyaoewar9nyan349reawr
str2を「nyan」とした。

出力結果

start
false [p1:yanyaoewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:anyaoewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:nyaoewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
true [p1:yaoewar9nyan349reawr] [p2:yan]
true [p1:aoewar9nyan349reawr] [p2:an]
true [p1:oewar9nyan349reawr] [p2:n]
false [p1:yaoewar9nyan349reawr] [p2:nyan] p1 pointer moves 2
false [p1:aoewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:oewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:ewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:war9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:ar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:r9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:nyan349reawr] [p2:nyan] p1 pointer moves -1
true [p1:yan349reawr] [p2:yan]
true [p1:an349reawr] [p2:an]
true [p1:n349reawr] [p2:n]
true [p1:349reawr] [p2:]
end
p2 is [], [349reawr] - ([] - [nyan]) = [nyan349reawr]
result is nyan349reawr

解説

p1のp2の1文字目を比較して

  • 一致したら次の文字を比較、すなわち先頭文字を削る(p1++;p2++;)…①
  • 一致しなかったらp1のポインタの位置をp2-s2-1分移動し、(p1 -= p2 - s2 - 1;)し、p2の文字列を元に戻す(p2=s2;)…②

p2-s2-1分、ポインタを移動するというのは、
①でp1を何度インクリメントしたかで結果が変わる

  • 0回なら1個左に移動
  • 1回なら移動しない
  • 2回なら1個右に移動
  • 3回なら2個右に移動

って感じ

そのとき、p1の文字列の状態は、
ポインタが、

  • 1個左に移動したら、p1から1文字を削除
  • 移動しないなら、p1を変更しない
  • 1個右に移動したら、p1を1文字復元
  • 2個右に移動したら、p1を2文字復元

って感じ

ループは、以下の条件を満たすまで回り続ける。

  • ①が呼ばれることでp2のポインタが文字列外へ移動するか
  • ②が呼ばれることでp1のポインタが文字列外へ移動するか

戻り値は、
p2のポインタの先頭が

  • 存在すれば、NULL
  • 存在しなければ、p2と一致した位置のp1のポインタ

を返す。