YoheiM.NET - 世の中をさらに便利に、面白くhttp://www.yoheim.net/YoheiM.NET - 世の中をさらに便利に、面白くyoheiM[CSS] 上下左右中央に表示する5つの方法(IE, Edge, Chrome, Safari, Firefoxに対応) http://www.yoheim.net/blog.php?q=20200601 こんにちは、@yoheiMuneです。
マークアップする際に「上下左右中央に表示したい」という要件はよく出てきます。今日はその実装方法をブログに書きたいと思います。5つあるので、色々な状況に応じたものを選んで使えると思います。



目次




なぜこの記事を書くのか

プログラミングスクールの講師をしていて、上下左右中央に表示する方法をアドバイスさせて頂く機会もあり、ブログにまとめておきたいと思ったのが執筆のきっかけです。複数の実現方法を提示することで様々な条件に応じることができますし、また各種ブラウザ(IE、Edge、Chrome、Safari、Firefox)の対応状況も確認済みなので、品質の良いコーディングができると思います。

これからWebページ制作をされる方に、少しでも役立てたらいいなと思います。



方法1:absolute + top,left=50% + ネガティブマージン

position: absoluteで絶対配置する際に、topleft50%として真ん中を指定して、要素の横幅と縦幅それぞれ半分をネガティブマージンとして設定する(=マイナス値をmarginに指定する)ことで、上下左右中央に表示することができます。
<div class="container">
    <div class="item"></div>
</div>
<style>
    .container {
        position: relative;
        width: 300px;
        height: 300px;
    }
    .item {
        /* 要素の大きさを指定する */
        width: 150px;
        height: 150px;

        /* top と left に 50% を指定して、要素の左上を中央にする. */
        position: absolute;
        top: 50%;
        left: 50%;

        /* 要素の大きさの半分をネガティブマージンとすることで、要素を画面中央にする. */
        margin-top: -75px;
        margin-left: -75px;
    }
</style>

(表示例)

(サポートブラウザ)

IE11 Edge Chrome Safari Firefox



方法2:absolute + top,left=50% + translate

方法1と似ていますが、ネガティブマージンの代わりにtranslateを使います。translateで縦横それぞれ半分の長さずつ動かすことで、上下左右中央に表示できます。こちらの方法は、要素の大きさが可変でも中央に表示できるので、柔軟性があります。
<div class="container">
    <div class="item">おはよう<br>こんにちは<br>おやすみなさい</div>
</div>
<style>
    .container {
        position: relative;
        width: 300px;
        height: 300px;
    }
    .item {
        /* top と left に 50% を指定して、要素の左上を中央にする. */
        position: absolute;
        top: 50%;
        left: 50%;

        /* tarnslate で要素の縦横それぞれ50%分の長さを動かすことで、要素を中央にする. */
        transform: translate(-50%, -50%);
    }
</style>

(表示例)

おはよう
こんにちは
おやすみなさい

(サポートブラウザ)

IE11 Edge Chrome Safari Firefox



方法3:absolute + top,bottom,left,right=0 + width,height + margin=auto

この方法は少し手品のようですが、次の4つの条件が成立する場合、上下左右中央に表示されます。
  1. positionabsoluteである
  2. top, bottom, left, rightが全て0である(※)
  3. marginautoである
  4. width,heightauto以外である

※ 正確には0である必要はありませんが、0にすることが多いです。詳細は後述の説明リンクをご参照ください。

<div class="container">
    <div class="item"></div>
</div>
<style>
    .container {
        position: relative;
        width: 300px;
        height: 300px;
    }
    .item {
        /* 1. absolute にする. */
        position: absolute;

        /* 2. top, bottom, left, right を 0 にする. */
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;

        /* 3. width, height を auto 以外にする. */
        width: 150px;
        height: 150px;

        /* 4. margin を auto にする. */
        margin: auto;
    }
</style>

(表示例)

(サポートブラウザ)

IE11 Edge Chrome Safari Firefox
上記はちょっと不思議ですが、cssの仕様でそのように動作します。詳細は「position: absolute; の指定で要素が上下左右中央配置になる理由」を読んでみてください。



方法4:display=flex

display: flexalign-items: centerjustify-content: center を使うと、簡単に上下中央寄せにできます。絶対配置でない場合に中央表示にするなら、この方法がシンプルで便利です。
<div class="container">
    <div class="item">おはよう<br>こんにちは<br>おやすみなさい</div>
</div>
<style>
    .container {

        /* flexbox を用いて、上下左右中央に表示します. */
        display: flex;
        align-items: center;
        justify-content: center;

        width: 300px;
        height: 300px;
    }
    .item {
        /* 中身の要素はCSSの指定なしでOK */
    }
</style>

(表示例)

おはよう
こんにちは
おやすみなさい

(サポートブラウザ)

IE11 Edge Chrome Safari Firefox
Bootstrap4 でも積極的に採用されている方法で、様々なサイトで利用されています。



方法5:vertical-algin=middle

少し古典的な方法ですが、display: tabledisplay: table-cellを用いてテーブル表現を行い、vertical-align: middleで上下中央表示に、text-align: centerで左右中央に表示できます。
<div class="container">
    <div class="item"><span>おはよう<br>こんにちは<br>おやすみなさい</span></div>
</div>
<style>
    .container {

        /* table 要素として表示する. */
        display: table;
        width: 300px;
        height: 300px;
    }
    .item {
        /* table-cell 要素として表示する. */
        display: table-cell;

        /* 上下中央に表示. */
        vertical-align: middle;

        /* 左右中央に表示. */
        text-align: center;
    }
</style>

(表示例)

おはよう
こんにちは
おやすみなさい

(サポートブラウザ)

IE11 Edge Chrome Safari Firefox
あまり使う機会はありませんが、htmlからPDF生成をするためのツール(phpwkhtmltopdf(Laravelなどで利用)wicked_pdf(Railsで利用))では、Flexboxがサポートされていないので、上記の方法で上下中央表示を実現することがあります。



最後に

今回紹介した5つのいずれかが、ご覧いただいた方の要件に合う方法であることを祈っています。このようなノウハウはこれからもどんどんと執筆したいと思います。

最後になりますが本ブログでは、フロントエンド、サーバー、PHP、Python、インフラ、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!



]]>
yoheiMThu, 11 Jun 2020 10:50:54 10JunJST
[シェル] grepで前後の行も表示して、エラーログ調査を楽にしよう http://www.yoheim.net/blog.php?q=20200401 grepでヒットした行の前後を表示できると、エラー調査の時などにとても役立ちます。今日は、grepで前後の行を表示する方法をブログに書きたいと思います。



目次




なぜ、grepで前後の行を表示したいのか

目的は色々あると思いますが、僕はエラーログを調査するときに前後の行を表示します。エラーログの前には直前の作業のログが、後ろにはスタックトレースが出力されていることが多いです。grepでエラーログの前後も表示することで、エラー内容の特定に加えて、原因調査もできるので便利です。

以下で実際にやってみたいと思います。



grepで該当した行の前後を表示する

ヒットした行の前後を表示するには、下記のように実行します。
# 前後3行を表示する
$ grep -3 "ERROR" [ファイルパス]

# 前3行を表示する
$ grep -B 3 "ERROR" [ファイルパス]

# 後ろ3行を表示する
$ grep -A 3 "ERROR" [ファイルパス]

例えば、前後3行を表示すると、何をしていて、どんなエラーになったのか、を把握できるようになります。
# 前後3行を表示して、エラーの内容把握
$ grep -3 "ERROR" storage/logs/laravel-2020-04-03.log

# 以下出力内容

# 前3行(直前の作業)
[2020-04-03 10:40:02] local.INFO: user_id=1がログイン。
[2020-04-03 10:40:02] local.INFO: user_id=1がタスク(id=123)を作成。
[2020-04-03 10:40:02] local.INFO: user_id=1が発注書(id=123)を作成。

# grepでヒットした行
[2020-04-03 10:46:42] local.ERROR: Class App\Http\Controllers\TaskPreviewRequest does not exist. user_id=1.

# 後ろ3行(エラーのスタックトレースの一部)
[stacktrace]
#0 /var/www/html/myapp/vendor/laravel/framework/src/Illuminate/Routing/RouteSignatureParameters.php(25): ReflectionParameter->getClass()
#1 [internal function]: Illuminate\\Routing\\RouteSignatureParameters::Illuminate\\Routing\\{closure}(Object(ReflectionParameter))
この場合、TaskPreviewRequestがないというエラーであることが分かります。また直前の行から、影響範囲はタスク作成や発注書作成周りであることが分かり、後ろの行から原因はリファクタリングの対応漏れかなと推測できます。



grepについてさらに詳しく

grepコマンドは使いこなすと非常に探し物が早くなります。以下の記事もぜひご覧ください。

[シェル] Grepでand検索、or検索、not検索、正規表現、再帰的に検索、圧縮ファイル内検索、など行う


最後に

最近は本番稼働中のシステムを調査をする仕事もあり、構成がわからない中でgrepを使いながら該当のファイルを探すことも多いです。Linuxコマンドが使えるようになるともっと作業効率化できるなと感じています。学んだことはブログにも書いていきたいと思います。

最後になりますが本ブログでは、サーバー、フロントエンド、PHP、Python、インフラ、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!



]]>
yoheiMThu, 23 Apr 2020 11:58:07 11AprJST
[フロントエンド] Reduxの考え方をシンプルに理解しよう(入門記事) http://www.yoheim.net/blog.php?q=20191201 こんにちは、@yoheiMuneです。
Reduxという考え方は、React、Vue、Swift、Kotlin、とクライアントアプリ界隈で非常に流行っています。今日はその考え方をシンプルに学びたいと思い、ライブラリを使わずにReduxとは何かを説明したいと思います。
Reduxの全体像


目次




この記事の目的

この記事では、Reduxを初めて学ぶ人や、一度は触れたけど挫折した人向けに、Reduxとはどのようなものかを解説しています。僕自身、いろいろな案件でReduxを使っていますが、少しもやっとしたところもあり、整理したいなと思い執筆しました。

Reduxはデータを扱うための考え方の1つです。Reduxという考え方を実現したライブラリが存在します(reduxやreact-reduxなど)。ただ、考え方を学ぶ上でライブラリを使うとわかりづらい点があります。ライブラリの中でいい感じに処理してくれる(=処理が隠蔽されている)部分があるためです。そのため、今回はあえて、ライブラリを使わずに、素のJavaScriptを実装しながらReduxの考え方を学びたいと思います。

なお、Reduxのライブラリは、コンパイルすると2KBほどの小さなライブラリで、コード全量を読むこともそんなに大変ではありません。この記事を読んだ後に、気になる方はライブラリのコードも覗いてみてください。この記事で見た用語や関数名を見つけることができ、理解が進むと思います。



Reduxを構成する要素

前述でも触れましたが、Reduxはデータを扱う考え方の一つです。Reduxでは、アプリケーションで扱うデータ全てを、1つの変数(stateと呼びます)で管理します。

Reduxのstateのイメージ
その、ステート(state)を管理するために、ストア( store)というものがあり、ステートを変更する際に、アクション(action)、ディスパッチ(dispatch)、リデューサー(Reducer)、というものがあります。ステートの変更を受け取るために、サブスクライブ(subscribe)という機能もあります。急にいっぱい出てきて混乱しますが、現時点では理解していなくて問題ありません。

Reduxの全体像を示します。

Reduxの全体像
Reduxが難しく感じるポイントは、この用語の多さだと思います。
1つずつ話を進めていきたいと思います。



ステート(state)

それでは早速、構成要素を1つずつ見ていきたいと思います。まずはステート(state)です。
ステート(state)は、アプリケーションで扱う全データを保持するオブジェクトです。大きな1つのJSONと考えるわかりやすいかもしれません。
ここでは、タイトル(title)とカウント(count)を保持するオブジェクトとしましょう。
// ステート
{
    title : '',
    count : 0
}
ただのJavaScriptオブジェクトですね!全く怖くありません(笑)。
このステートを、Reduxという考え方で管理したいと思います。



ストア(store)

上記のステートを管理する人(管理者)として、ストア(store)というものを定義します。Reduxの全体像のイメージで示した通り、ストア(store)がステート(state)を保持します(Store has State)。
// ストア
const store = {

    // ストアが、ステートを、保持している.
    state : {
        title : '',
        count : 0
    }
}
ストアの中に、ステートがあります。これもわかりやすいですね、簡単なJavaScriptです。
Reduxでは、ストアがステートを保持していて、ステートの変更はストアが行います。



ステートの値を変更する

それではステートの中身を変更したいと思います。ステートを変更する場合、アクション(action)、ディスパッチ(dispatch)、リデューサー(Reducer)の3つを使います。

ここでは「ステートの中のcountを1つ増やす」ことを考えてみたいと思います。


アクション(Action)
ストアに変更したい内容を伝えるため、アクション(action)を作成します。アクションは変更指示書のようなものです。
// アクション.
const action = {
    type : 'ADD_COUNT'
}
アクションも簡単なJavaScriptオブジェクトですね!
アクションにはtypeという決まった項目を用意し、その項目に指示を書きます。ここではADD_COUNTという文字列を指定しました。


ディスパッチ(dispatch)
指示書を作っても、それがストアに届かなければ意味がありません。ストアに届けるために、ディスパッチ(dispatch)を使います。
ストア(store)にdispatchというメソッドを用意し、引数でアクションを受け取ります。
const store = {

    // 上記のステートを、ストアは保持している.
    state : {
        title : '',
        count : 0
    },

    // ディスパッチを追加.
    dispatch : function (action) {
        // あとで実装します.
    }
}
これで、ストアにアクションを渡すことができます。


リデューサー(reducer)
ストアは受け取ったアクションを読み取って、ステートを変更します。アクションの内容を理解してステートを変更する処理を担当するのが、リデューサー(reducer)です。

ここではまず、リデューサー(reducer)の処理を定義したいと思います。
リデューサー(reducer)は、現在のステートとアクションを引数で受け取り、変更後の新しいステートを返却する関数として定義します。
// リデューサー(reducer).
// @param state 現在のステート
// @param action 変更内容
function myReducer(state, action) {

    // actionのタイプごとに、処理を分ける
    switch (action.type) {

        // ADD_COUNTの場合は、countを1増やす.
        case 'ADD_COUNT':
            state = {
                ...state,
                count : state.count + 1
            }
            return state

        default:
            return state
    }
}
リデューサーの中ではアクションのtype項目を見て、それぞれに応じた処理を行います。ここではtypeADD_COUNTの場合に、ステート内のcountに1加えています。

これで、アクション内容を理解してステートを変更する処理(=リデューサー)を作成できました。

なおReduxでは、既存のステートを変更するのではなく、新しいステートを毎回作成します。
// 新しいステートのオブジェクトを作成している.
state = {
    ...state,
    count : state.count + 1
}
これはReduxの3原則の一つ「State is read-only」でとても大切なことですが、最初のうちは気にしなくて良いと思います。まずは大枠を掴むことが大切です。

上記で作成したmyReducerを、storeに設定します。
// Store に reducer を追加.
const store = {

    state : {
        title : '',
        count : 0
    },

    // リデューサー.
    reducer : myReducer,

    dispatch : function (action) {
        // あとで実装します.
    }
}
これで、ストアがリデューサーを使えるようになりました。

そして、このreducerdispatchメソッドの中で使うことで、ステートを変更できるようになります。
// dispatch メソッド内で、reducer を使う.
const store = {

    state : {
        title : '',
        count : 0
    },

    reducer : myReducer,

    dispatch : function (action) {
        // reducer を使って、state を変更する.
        this.state = this.reducer(this.state, action)
    }
}
これで、ストア内のステートを変更できました。



実際に、Action → Dispatch → Reducer で State を変更してみる

実際に値を変更してみましょう。上記を実装した状態で、下記のコードを実行します。
// アクションを定義.
const action = {
    type : 'ADD_COUNT'
}

// 動作テスト
store.dispatch(action)
console.log('1回目:', store.state)  // 1回目: {title: "", count: 1}

store.dispatch(action)
console.log('2回目:', store.state)  // 2回目: {title: "", count: 2}

store.dispatch(action)
console.log('3回目:', store.state)  // 3回目: {title: "", count: 3}
無事に、アクション、ディスパッチ、リデューサー、を使って、ステートの値を変更できました。

実際にReduxのライブラリを使う場合には、store.stateとプロパティに直接アクセスするのではなく、store.getState()と関数を通してステートを取得します。
ここでもそれにならって、getStateメソッドを定義したいと思います。
// Store.
const store = {

    /* 省略 */

    // ステートを取得するメソッドを追加.
    getState : function () {
        return this.state
    }
}
上記のメソッドを使って、ステートを取得しましょう。
store.dispatch(action)
console.log('4回目:', store.getState())  // 4回目: {title: "", count: 4}
無事にステートを取得することができました。



変更を検知する(サブスクライブ(subscribe))

さて、ステートを変更するのが自分であればステート変更のタイミングは分かりますが、誰か他の人が(=他の処理が)更新した時には、ステートがいつ変更されたのかわかりません。他の人がステートを変更した際に、その変更を教えてもらうのが、サブスクライブ(subscribe)という機能です。

ストア内にsubscribeというメソッドを用意して、変更があった時に呼び出してもらう関数を登録できるようにしましょう。
// Store.
const store = {

    /* 省略  */

    // 変更時に呼び出す関数を保持する変数.
    subscribers : [],

    // 引数で受け取った関数を、subscribers変数に追加する.
    subscribe : function (fn) {
        this.subscribers.push(fn)
    }
}
そして、subscribersに登録された関数を、ストアのdispatchメソッドの中で呼び出し、ステート変更を通知します。
// Store.
const store = {

    /* 省略. */

    dispatch : function (action) {
        this.state = this.reducer(this.state, action)

        // ステートの変更後、変更を通知する.
        this.subscribers.forEach(function (subscriber) {
            subscriber()
        })
    },

    subscribers : [],

    subscribe : function (fn) {
        this.subscribers.push(fn)
    }
}
これで、サブスクライブ(subscribe)の実装ができました。

実際に使ってみたいと思います。
// ストアにサブスクライブを追加.
store.subscribe(function () {
    console.log('subscribe:', store.getState())
})

// ステートを変更する(1回目)
store.dispatch(action)     // subscribe: {title: "", count: 1}

// ステートを変更する(2回目)
store.dispatch(action)     // subscribe: {title: "", count: 2}
ステートに変更があった場合に、変更を検知することができました。



Reduxのメリット

さて最後に、Reduxを導入するメリットを考えてみたいと思います。こんなに大変なデータ管理をする必要があるのでしょうか。正直なところ、メリットを感じないうちは使う必要はありません。ただ、大きめなプロダクトを開発する時には、下記3つのメリットが生きてきます。

  1. データの変更方法が制限されている
  2. データの変更を検知する術がある
  3. 離れたコンポーネント間でデータのやり取りができる

「1. データの変更方法が制限されている」は一見不便そうですが、プロダクトが大きくなるとメリットがあります。データを変更する方法が限られるので、「このデータ、誰が変えたの?」という問題が発生しても、すぐに調べて原因を特定できます。データの更新方法が制限されていたり、データの更新者が制限されることで、アプリケーションのデータの堅牢性が上がります。

「2. データの変更を検知する術がある」は、Reduxの「サブスクライブ(subscribe)」という機能です。例えば、画面ヘッダーのコンポーネントで、「誰が更新したかはわからないけど、ステートの中のtitleが変わったら、自分の表示を更新しよう」といった実装ができるようになります。変更を通知してくれる仕組みは非常に便利です。

最後に「3. 離れたコンポーネント間でデータのやり取りができる」は、「2. データの変更を検知する術がある」とも関連しますが、例えばスレッドを表示する画面があったとします。「スレッドが切り替わるたびに、スレッド名を画面ヘッダーに反映したい。僕(=スレッド画面)はステートのtitleを更新すれば、君(=画面ヘッダー)がそれをサブスクライブしているから自動的に変更してくれるよね、ありがとう」といった使い方ができます。
特にReactなど、親子関係以外のコンポーネント間でデータをやり取りしたい場合に便利です。

他にもメリットがあると思いますが、Reduxを使うことで上記のメリットを享受できます。



参考サイト

Reduxの本家ページなど、リンクを掲載します。英語ですが、読むとためになります。

redux.js.org(本家ページ)

redux | Github(コードが読めます)



最後に

今日はReduxのチュートリアルを書きました。本記事で紹介したコードはどれも簡単なものなので、ぜひ実装してみてください。理解に役立ちます。

なお、Reduxの全体像を把握することを主眼としているため、実装内容の一部がReduxに準拠していない場合もあります。実際にReduxを使う場合は、Reduxのライブラリを使うと良いと思います。

最後になりますが本ブログでは、フロントエンド、PHP、Python、インフラ、サーバー、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!



]]>
yoheiMTue, 10 Dec 2019 16:27:35 16DecJST
[JavaScript] 全角カナ、半角カナの判定を行う方法 http://www.yoheim.net/blog.php?q=20191105 こんにちは、@yoheiMuneです。
先日は「[JavaScript] 全角⇔半角の変換を行う(英数字、カタカナ)」のブログを書きました。今回は、JavaScriptで日本語カナのチェックを行う実装をブログに書きたいと思います。
氏名カナの入力チェックなどで使うことができます。



目次




全角カナのチェックを行う


基本形
文字列が全角カナであるかを判定するためには、下記の実装で判定できます。
// 全角カナの判定.
function isZenkakuKana(s) {
    return !!s.match(/^[ァ-ヶー ]*$/);  // 「 」は全角スペースです.
}
下記のように利用します。
isZenkakuKana('シブヤ');  // true

派生系(許可する文字種類を増やしたい場合)
また、全角数字など、許可したい文字列を追加することもできます。
// 全角カナ、全角数字、を許可
function isZenkakuKana(s) {
    return !!s.match(/^[ァ-ヶ0-9ー ]*$/);
}

// 全角カナ、全角数字、半角数字、を許可
function isZenkakuKana(s) {
    return !!s.match(/^[ァ-ヶ0-90-9ー ]*$/);
}

// 全角カナ、全角数字、半角数字、半角スペース、を許可
function isZenkakuKana(s) {
    return !!s.match(/^[ァ-ヶ0-90-9ー  ]*$/);
}
全角カナの入力欄ですが、要件によっていろいろなので、上のバリエーションで要件に合うものを使えると良いかなと思います。



半角カナのチェックを行う


基本形
文字が半角カナであるかを判定する関数は、下記です。
// 半角カナのチェック.
function isHankakuKana(s) {
    return !!s.match(/^[ヲ-゚]*$/);
}
ヲ-゚」の範囲は、「ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚」を表します。

下記のように利用します。
isHankakuKana('シブヤ')  // true

派生系(許可する文字種類を増やしたい場合)
半角スペースや半角数字など、他の文字も許可したい場合には、下記のように実装します。
// 半角カナ、半角スペース、を許可
function isHankakuKana(s) {
    return !!s.match(/^[ヲ-゚ ]*$/);
}

// 半角カナ、半角スペース、半角数字、を許可
function isHankakuKana(s) {
    return !!s.match(/^[ヲ-゚ 0-9]*$/);
}
半角カナチェックも要件がいろいろなので、その時に応じて対応できたら素敵です。



関連記事

カナの全角と半角の相互変換を行う方法」もブログに書きました。もし良ければご参考ください。



最後に

業務用のアプリケーションの場合、カナを扱うことも多いので、ノウハウを残しておければと思いブログに書きました。実装がすぐにできれば、より多くの価値を生み出せると思いますので、今後も実装の役に立つネタをブログに書いていけたらと思っています。

最後になりますが本ブログでは、PHP、フロントエンド、Python、インフラ、サーバー、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!



]]>
yoheiMWed, 20 Nov 2019 11:05:58 11NovJST
<h2 data-category="PHP">DBからの検索結果をPHPで並び替える(array_multisortの利用、昇順、降順、複数のソートキー、ユーザー定義ソート) http://www.yoheim.net/blog.php?q=20191104DBからの検索結果をPHPで並び替える(array_multisortの利用、昇順、降順、複数のソートキー、ユーザー定義ソート)
こんにちは、@yoheiMuneです。
先日は「PHPの連想配列のソートいろいろ」を書きました。
今日は、データベースからの取得した結果(配列の中に複数の連想配列が含まれているもの、いわゆる多次元配列)を、array_multisort関数を用いて、並び替える方法をブログに書きたいと思います。



目次




今回説明に使うデータ

以下のような、配列の中に連想配列が入ったもの(=多次元配列)を使いたいと思います。
$fruits = [
  array('id' =>'01', 'name' => 'apple'),
  array('id' =>'02', 'name' => 'orange'),
  array('id' =>'03', 'name' => 'pinapple')
];
フルーツの一覧を、データベースから取得した時のデータ構造のイメージです。



任意のキーで、昇順に並び替える

まずは、並び替えに使うキーを決めます。ここではid列の値で並び替えたいと思います。
idの昇順に並び替えるには、array_multisort()を用いて実装します。
// id の昇順に並び替える.

// 並び替えの基準を取得します.
$ids = [];
foreach($fruits as $fruit) {
    $ids[] = $fruit['id'];
}

// PHP5.5以降では、下記の書き方でもOK.
$ids = array_column($fruits, 'id');

// idの昇順(SORT_ASC)に並び替える.
array_multisort($ids, SORT_ASC, $fruits);

// Array
// (
//     [0] => Array
//         (
//             [id] => 01
//             [name] => apple
//         )

//     [1] => Array
//         (
//             [id] => 02
//             [name] => orange
//         )

//     [2] => Array
//         (
//             [id] => 03
//             [name] => pinapple
//         )
// )



任意のキーで、降順に並び替える

idの降順に並び替えるには、ソート順にSORT_DESCを指定します。
// id の降順に並び替える.

// 並び替えの基準を取得します.
$ids = array_column($fruits, 'id');

// idの降順(SORT_DESC)に並び替える.
array_multisort($ids, SORT_DESC, $fruits);

// Array
// (
//     [0] => Array
//         (
//             [id] => 03
//             [name] => pinapple
//         )

//     [1] => Array
//         (
//             [id] => 02
//             [name] => orange
//         )

//     [2] => Array
//         (
//             [id] => 01
//             [name] => apple
//         )
// )



複数のキーを使って、並び替える

今までは1つのキーのみで並び替えしていましたが、複数のキーでもソートできます。
// 今回使うデータ.
// 第1ソートキー(volume)に同じ値があり、一意にソートできないので、
// 第2ソートキー(edition)も指定します.
$data = [];
$data[] = array('volume' => 67, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 1);
$data[] = array('volume' => 85, 'edition' => 6);
$data[] = array('volume' => 98, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 6);
$data[] = array('volume' => 67, 'edition' => 7);

// 第1ソートキー(volume)
$volume  = array_column($data, 'volume');

// 第2ソートキー(edition)
$edition = array_column($data, 'edition');

// データを volume の降順、edition の昇順にソートします.
// $data を最後のパラメータとして渡し、同じキーでソートします.
array_multisort($volume, SORT_DESC, $edition, SORT_ASC, $data);

// Array
// (
//     [0] => Array
//         (
//             [volume] => 98
//             [edition] => 2
//         )

//     [1] => Array
//         (
//             [volume] => 86
//             [edition] => 1
//         )

//     [2] => Array
//         (
//             [volume] => 86
//             [edition] => 6
//         )

//     [3] => Array
//         (
//             [volume] => 85
//             [edition] => 6
//         )

//     [4] => Array
//         (
//             [volume] => 67
//             [edition] => 2
//         )

//     [5] => Array
//         (
//             [volume] => 67
//             [edition] => 7
//         )
// )



ユーザー独自定義の並び順で並び替える

usort()を使うと、並び順を自由に定義できます。ここではname列の文字数で並び替えをしてみました。
// ユーザー独自定義のソート.
usort($fruits, function ($f1, $f2) {
    // ここでは name の文字数の多い順に並べています.
    return strlen($f2['name']) - strlen($f1['name']);
});

// Array
// (
//     [0] => Array
//         (
//             [id] => 03
//             [name] => pinapple
//         )
//     [1] => Array
//         (
//             [id] => 02
//             [name] => orange
//         )
//     [2] => Array
//         (
//             [id] => 01
//             [name] => apple
//         )
// )



参考資料

array_multisort()の公式マニュアルは下記です。

https://www.php.net/manual/ja/function.array-multisort.php



最後に

DBからの取得結果をPHPで並び替えるにはどうしたらいいんだろう、と調べたのがきっかけでarray_multisort()を知りました。しかし、最初は使い方がいまいち理解できずでしたが、サンプルを実装してみたり、ブログに書いてみることで理解できました。

最後になりますが本ブログでは、PHP、フロントエンド、Python、インフラ、サーバー、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!



]]>
yoheiMSat, 16 Nov 2019 07:32:52 7NovJST
[PHP] 連想配列を並び替えする方法(キーでのソート、値でのソート、ソート順の独自定義) http://www.yoheim.net/blog.php?q=20191103 こんにちは、@yoheiMuneです。
PHPの連想配列は柔軟に使えて便利ですよね。今日は、連想配列の中身を並び替える方法を、ブログに書きたいと思います。


目次




ソートの説明に使う連想配列

このブログでは、以下の連想配列を使って、ソートを説明します。
$fruits = [
  '01' => 'apple',
  '02' => 'orange',
  '03' => 'pinapple'
];



キーでのソート(昇順、降順、ユーザー定義)

キーでの並び替えは、連想配列のキー(010203)を使ってソートします。
昇順ソートにはksort()、降順ソートにはkrsort()、ユーザー定義によるソートにはuksort()を使います。
// キーで昇順ソート
ksort($fruits);

// Array
// (
//     [01] => apple
//     [02] => orange
//     [03] => pinapple
// )
// キーで降順ソート
krsort($fruits);

// Array
// (
//     [03] => pinapple
//     [02] => orange
//     [01] => apple
// )
// ユーザー定義によるソート
// (ここでは、キーの昇順に並べています)
uksort($fruits, function ($key1, $key2) {
   return intval($key1) - intval($key2); 
});

// Array
// (
//     [01] => apple
//     [02] => orange
//     [03] => pinapple
// )



値でのソート(昇順、降順、ユーザー定義)

値での並び替えは、連想配列の値(appleorangepinapple)を使ってソートします。
昇順ソートにはasort()、降順ソートにはarsort()、ユーザー定義によるソートにはuasort()を使います。
// 値で昇順ソート
asort($fruits);

// Array
// (
//     [01] => apple
//     [02] => orange
//     [03] => pinapple
// )
// 値で降順ソート
arsort($fruits);

// Array
// (
//     [03] => pinapple
//     [02] => orange
//     [01] => apple
// )
// ユーザー定義によるソート
// (ここでは、値の文字数が多い順に並べています)
uasort($fruits, function ($value1, $value2) {
   return strlen($value2) - strlen($value1);
});

// Array
// (
//     [03] => pinapple
//     [02] => orange
//     [01] => apple
// )



関連:連想配列(多次元配列)をソートするには

以下のような多次元配列をソートする方法もブログに書きました。良ければ合わせてご確認ください。
// 多次元配列の例(DBの検索結果など)
$fruits = [
  array('id' =>'01', 'name' => 'apple'),
  array('id' =>'02', 'name' => 'orange'),
  array('id' =>'03', 'name' => 'pinapple')
];

[PHP] 連想配列(多次元配列)をソートする(昇順、降順、ユーザー独自ソート、複数のソートキー)



参考資料

PHPの配列並び替えについてのマニュアルです。今回紹介したもの以外にも関数があります。

https://www.php.net/manual/ja/array.sorting.php



最後に

PHPでの実装をしていると、ちょっとしたことを調べることも多いので、少しずつノウハウを貯めてたいなと思っています。PHPには沢山の便利な関数が用意されていて、それらを知ると知らないとでは効率が大きく変わるので、1つずつ学べると良いなと思います。

最後になりますが本ブログでは、PHP、フロントエンド、Python、インフラ、サーバー、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!



]]>
yoheiMFri, 15 Nov 2019 17:01:49 17NovJST
[PHP] 関数から複数の値を返す。複数の変数で一度に受け取る(タプル代入) http://www.yoheim.net/blog.php?q=20191102 PHPの関数はarray()を用いて複数の値を返却できます。またそれらの値をlist()を用いて、複数の変数へ一気に代入できます。今日はその実装方法をブログに書きたいと思います。



目次




関数で、複数の値を返す

PHPの関数で複数の値を返したい場合、array()を用いて複数の値を返却できます。
function getPerson() {
    $name = 'Yohei';
    $age = 33;
    return array($name, $age);
}

$person = getPerson();
echo $person;  // [ 'Yohei', 33 ]
配列に複数の値を入れて返す、というのはシンプルで分かりやすいですね。



list()を用いて、複数の変数に一括代入する

PHPでは、list()を用いて、複数の値を複数の変数に一度に代入できます。
list($name, $age) = array('Yohei', 33);
echo $name;  //'Yohei'
echo $age;   //33
また、PHP7.1以降では配列記述で受け取ることもできます。
[ $name, $age ] = array('Yohei', 33);
echo $name;  //'Yohei'
echo $age;   //33
なお他の言語では、この機能をタプル展開やタプル代入と呼ぶ場合があります。



関数で複数の値を返却して、list()で複数変数に一括代入する

上記2点を組み合わせると、関数からの複数の戻り値を、複数の変数に一度で代入できます。
// 配列で複数の値を返却する.
function getPerson() {
    $name = 'Yohei';
    $age = 33;
    return array($name, $age);
}

// list() で一気に受け取る.
list($name, $age) = getPerson();
echo $name;  //'Yohei'
echo $age;   //33
関数からの戻り値を複数で扱えるようになると、実装幅がグッと拡がります。



最後に

今回の内容は実装幅が広がりますし、コードもシンプルになるので、知っていて損はないと思います。少しずつPHPでの開発ノウハウも貯めていきたいなと思っています。

最後になりますが本ブログでは、PHP、フロントエンド、Python、インフラ、サーバー、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!



]]>
yoheiMTue, 12 Nov 2019 10:02:27 10NovJST
[JavaScript] 全角⇔半角の変換を行う(英数字、カタカナ) http://www.yoheim.net/blog.php?q=20191101 数字、アルファベット、カタカナの全角半角変換は、JavaScriptで簡単に実現できます。今日はその実装方法をブログに書きたいと思います。



目次




全角 → 半角(英数字)

function hankaku2Zenkaku(str) {
    return str.replace(/[A-Za-z0-9]/g, function(s) {
        return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
    });
}

// 使用例
hankaku2Zenkaku('123abC');  // '123abC'
文字コード上で、全角英数字から65248引くと半角英数字になります。
また、処理範囲を正規表現で[A-Za-z0-9]と指定していますが、例えば[0-9]とすれば、変換対象を全角数字に限定できます。



半角 → 全角(英数字)

function zenkaku2Hankaku(str) {
    return str.replace(/[A-Za-z0-9]/g, function(s) {
        return String.fromCharCode(s.charCodeAt(0) + 0xFEE0);
    });
}

// 使用例
zenkaku2Hankaku('123abC');  // '123abC'
全角→半角とは逆で、半角英数字に65248加えると全角英数字になります。
全角→半角と同様に、正規表現の[A-Za-z0-9]を変更することで、処理対象を限定できます。



全角 → 半角(カタカナ)

カタカナの場合、文字コードの演算ではうまくできない部分があるので、マッピングを作成して対応します。
function zenkana2Hankana(str) {
    var kanaMap = {
         "ガ": "ガ", "ギ": "ギ", "グ": "グ", "ゲ": "ゲ", "ゴ": "ゴ",
         "ザ": "ザ", "ジ": "ジ", "ズ": "ズ", "ゼ": "ゼ", "ゾ": "ゾ",
         "ダ": "ダ", "ヂ": "ヂ", "ヅ": "ヅ", "デ": "デ", "ド": "ド",
         "バ": "バ", "ビ": "ビ", "ブ": "ブ", "ベ": "ベ", "ボ": "ボ",
         "パ": "パ", "ピ": "ピ", "プ": "プ", "ペ": "ペ", "ポ": "ポ",
         "ヴ": "ヴ", "ヷ": "ヷ", "ヺ": "ヺ",
         "ア": "ア", "イ": "イ", "ウ": "ウ", "エ": "エ", "オ": "オ",
         "カ": "カ", "キ": "キ", "ク": "ク", "ケ": "ケ", "コ": "コ",
         "サ": "サ", "シ": "シ", "ス": "ス", "セ": "セ", "ソ": "ソ",
         "タ": "タ", "チ": "チ", "ツ": "ツ", "テ": "テ", "ト": "ト",
         "ナ": "ナ", "ニ": "ニ", "ヌ": "ヌ", "ネ": "ネ", "ノ": "ノ",
         "ハ": "ハ", "ヒ": "ヒ", "フ": "フ", "ヘ": "ヘ", "ホ": "ホ",
         "マ": "マ", "ミ": "ミ", "ム": "ム", "メ": "メ", "モ": "モ",
         "ヤ": "ヤ", "ユ": "ユ", "ヨ": "ヨ",
         "ラ": "ラ", "リ": "リ", "ル": "ル", "レ": "レ", "ロ": "ロ",
         "ワ": "ワ", "ヲ": "ヲ", "ン": "ン",
         "ァ": "ァ", "ィ": "ィ", "ゥ": "ゥ", "ェ": "ェ", "ォ": "ォ",
         "ッ": "ッ", "ャ": "ャ", "ュ": "ュ", "ョ": "ョ",
         "。": "。", "、": "、", "ー": "ー", "「": "「", "」": "」", "・": "・"
    }
    var reg = new RegExp('(' + Object.keys(kanaMap).join('|') + ')', 'g');
    return str
            .replace(reg, function (match) {
                return kanaMap[match];
            })
            .replace(/゛/g, '゙')
            .replace(/゜/g, '゚');
};

// 使用例
zenkana2Hankana('アシタハイイテンキカナ、ブーヴー');  // 'アシタハイイテンキカナ、ブーヴー'
対応表に沿って、該当する文字を1つずつ変換しています。
上記の対応表以外にも対応したい文字があれば、マッピングに追加することで、処理対象に加えることができます。



半角 → 全角(カタカナ)

同じく、対応表(マッピング)を作成して対応します。
function hankana2Zenkana(str) {
    var kanaMap = {
        'ガ': 'ガ', 'ギ': 'ギ', 'グ': 'グ', 'ゲ': 'ゲ', 'ゴ': 'ゴ',
        'ザ': 'ザ', 'ジ': 'ジ', 'ズ': 'ズ', 'ゼ': 'ゼ', 'ゾ': 'ゾ',
        'ダ': 'ダ', 'ヂ': 'ヂ', 'ヅ': 'ヅ', 'デ': 'デ', 'ド': 'ド',
        'バ': 'バ', 'ビ': 'ビ', 'ブ': 'ブ', 'ベ': 'ベ', 'ボ': 'ボ',
        'パ': 'パ', 'ピ': 'ピ', 'プ': 'プ', 'ペ': 'ペ', 'ポ': 'ポ',
        'ヴ': 'ヴ', 'ヷ': 'ヷ', 'ヺ': 'ヺ',
        'ア': 'ア', 'イ': 'イ', 'ウ': 'ウ', 'エ': 'エ', 'オ': 'オ',
        'カ': 'カ', 'キ': 'キ', 'ク': 'ク', 'ケ': 'ケ', 'コ': 'コ',
        'サ': 'サ', 'シ': 'シ', 'ス': 'ス', 'セ': 'セ', 'ソ': 'ソ',
        'タ': 'タ', 'チ': 'チ', 'ツ': 'ツ', 'テ': 'テ', 'ト': 'ト',
        'ナ': 'ナ', 'ニ': 'ニ', 'ヌ': 'ヌ', 'ネ': 'ネ', 'ノ': 'ノ',
        'ハ': 'ハ', 'ヒ': 'ヒ', 'フ': 'フ', 'ヘ': 'ヘ', 'ホ': 'ホ',
        'マ': 'マ', 'ミ': 'ミ', 'ム': 'ム', 'メ': 'メ', 'モ': 'モ',
        'ヤ': 'ヤ', 'ユ': 'ユ', 'ヨ': 'ヨ',
        'ラ': 'ラ', 'リ': 'リ', 'ル': 'ル', 'レ': 'レ', 'ロ': 'ロ',
        'ワ': 'ワ', 'ヲ': 'ヲ', 'ン': 'ン',
        'ァ': 'ァ', 'ィ': 'ィ', 'ゥ': 'ゥ', 'ェ': 'ェ', 'ォ': 'ォ',
        'ッ': 'ッ', 'ャ': 'ャ', 'ュ': 'ュ', 'ョ': 'ョ',
        '。': '。', '、': '、', 'ー': 'ー', '「': '「', '」': '」', '・': '・'
    };

    var reg = new RegExp('(' + Object.keys(kanaMap).join('|') + ')', 'g');
    return str
            .replace(reg, function (match) {
                return kanaMap[match];
            })
            .replace(/゙/g, '゛')
            .replace(/゚/g, '゜');
};

// 使用例
hankana2Zenkana('アシタハイイテンキカナ、ブーヴー');  // 'アシタハイイテンキカナ、ブーヴー'
こちらも同じく、変換処理に追加したい文字があれば、対応表に追加することで対応できます。

なお、カタカナの全角半角の変換ルールは、プロジェクトやアプリケーションによって異なる場合があるので、上記と違う場合にはそれに応じて対応表を書き直す必要があります。



関連記事

[JavaScript] 全角カナ、半角カナの判定を行う方法」もブログに書きました。もし良ければ合わせてご覧ください。



最後に

サービス開発をしていて、全角と半角の変換処理を扱う機会が何度かあったので、ノウハウとして残しておきたいと思いブログにしました。コピペして使えるようになっておくとコーディングスピードが上がるので良いかなと思います。

最後になりますが本ブログでは、フロントエンド、Python、インフラ、サーバー、PHP、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!



]]>
yoheiMWed, 20 Nov 2019 11:08:23 11NovJST
<h2 data-category="Tool">Macに ElasticSearch と Kibana を導入する(Homebrew利用) http://www.yoheim.net/blog.php?q=20190903Macに ElasticSearch と Kibana を導入する(Homebrew利用)
こんにちは、@yoheiMuneです。
今日は、Macに ElasticSearch と Kibana をお手軽に導入する方法を書きたいと思います。ElasticSearch を使う場合に、ローカル環境で色々と実験できると何かと便利かなと思います。



目次




前提事項

本件では、Homebrewというパッケージ管理ソフトを利用します。インストールしていない方は、下記よりインストールしてご利用ください。

https://brew.sh(Homebrew本家 | 日本語)



ElasticSearchをインストールする

Homebrewがあれば簡単。ターミナルを起動し、以下のコマンドを実行すると、簡単にインストールできます。
$ brew update
$ brew install elasticsearch
どんなバージョンがインストールされるのかなどはログにも表示されますが、infoコマンドでも確認できます。
$ brew info elasticsearch

elasticsearch: stable 6.8.2, HEAD

...(以下省略)...



ElasticSearchを起動する

インストールするとelasticsearchコマンドが利用できるようになります。それを実行してElasticSearchを起動します。
$ elasticsearch
起動処理が始まるとログが出力され、起動が終わるとログ出力が収まります。

ターミナルで別タブを開いて、下記を実行し、ElasticSearchにアクセスできることを確認します。
$ curl localhost:9200

{
  "name" : "9nrEjYA",
  "cluster_name" : "elasticsearch_munesadayohei",
  "cluster_uuid" : "gPNEDmhrRymwwZCRzebhyw",
  "version" : {
    "number" : "6.8.2",
    "build_flavor" : "oss",
    "build_type" : "tar",
    "build_hash" : "b506955",
    "build_date" : "2019-07-24T15:24:41.545295Z",
    "build_snapshot" : false,
    "lucene_version" : "7.7.0",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}
停止するには、Ctrl + Cで停止できます。



ElasticSearchを起動する(バックグラウンド起動)

brew servicesコマンドを使うと、サービスとして起動できます。Mac再起動後にも、自動的に ElasticSearch を起動してくれます。
# サービスとして起動.
$ brew services start elasticsearch
なお、brew servicesには、以下のような機能が用意されています。
# サービス停止
$ brew services stop elasticsearch

# サービス一覧
$ brew services list

# サービス起動(ただし、ログイン時の起動登録はしない)
$ brew services run elasticsearch



Kibanaをインストールする

KibanaもHomebrewから簡単にインストールできます。
インストールできる内容をbrew infoコマンドで確認します。
$ brew info kibana

kibana: stable 6.8.2 (bottled), HEAD
...(以下省略)...
インストールします。
$ brew install kibana
無事にインストールできれば完了です。



Kibanaを起動する

インストールするとkibanaコマンドが使えるようになるので、それで起動します。
# Kibanaを起動する
$ kibana
もし事前にElasticSearchを起動していなければ、以下のエラーログが表示されます。
Unable to revive connection: http://localhost:9200/
No living connections
その場合は焦らず、ターミナルの別タブでElasticSearchを起動します(起動は上記を参照)。
接続できると、以下のログが表示されます。
Status changed from red to green - Ready
Server running at http://localhost:5601
ブラウザでKibanaにアクセスして、表示できることを確認します。
# ブラウザでアクセス
http://localhost:5601
なおKibanaも、brew servicesコマンドで、サービス登録&起動ができます。
# サービスとして起動.
$ brew services start kibana
お好みの起動方法でご利用ください。



最後に

いくつかの案件で ElasticSearch や Kibana を使っていますが、本格的に使おうと思い、ローカル環境を作成したのでその内容をブログに書きました。 Dockerでも良かったのですが、個人的にはお手軽なHomebrewが良かったので、今回はそちらで作成しました。

最後になりますが本ブログでは、Python、フロントエンド、インフラ、サーバー、PHP、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!



]]>
yoheiMFri, 20 Sep 2019 17:31:26 17SepJST
<h2 data-category="ツール">cronの日時指定を、基礎から学ぶ(分,時,日,月,曜日の指定、◯分ごと、月末起動、など) http://www.yoheim.net/blog.php?q=20190902cronの日時指定を、基礎から学ぶ(分,時,日,月,曜日の指定、◯分ごと、月末起動、など)
こんにちは、@yoheiMuneです。
今日は、cronの時間指定について基礎〜応用まで、ブログに書きたいと思います。



目次




cronの基本

cronは「* * * * *」の5箇所を指定して、起動時間を設定します。左から「分」「時」「日」「月」「曜日」を指定します。
# cronの起動時間設定
* * * * * (起動したい処理)
| | | | |
| | | | |- 曜日
| | | |--- 月
| | |----- 日
| |------- 時
|--------- 分
上記5箇所に値を設定することで、様々なタイミングで処理を起動できます。



起動時間の書き方(基本編)

ここではまず、基本的な時間指定の方法を見ていきたいと思います。

1分毎に起動する
すべての箇所に*を指定した場合、1分毎に処理が起動されます。
# 1分毎に起動する
* * * * * echo 'hello'

毎時◯分に起動する
「分」に数字を指定すると、毎時◯分で処理を起動できます。
# 毎時0分
0 * * * * echo 'hello'

# 毎時10分
10 * * * * echo 'hello'
また、カンマ区切りで複数指定したり、ハイフンを用いて範囲指定もできます。
# 毎時10分と30分(カンマで複数指定も可)
10,30 * * * * echo 'hello'

# 毎時00〜10分に、1分毎に起動(ハイフンで範囲指定も可)
0-10 * * * * echo 'hello'

毎日◯時に起動する
「時」「分」の2箇所を指定すると、日次(Daily)で起動できます。
# 毎日1時00分
0 1 * * * echo 'hello'

# 毎日1時と3時に、00分に起動(カンマで複数指定も可)
0 1,3 * * * echo 'hello'

# 毎日1時〜6時まで、00分に起動(ハイフンで範囲指定も可)
0 1-6 * * * echo 'hello'
1つ注意するべきことは、分を「*」にした場合、指定した時間(1時など)に1分毎に処理が起動してしまいます。
# 毎日1時台に1分ごとに起動してしまう(00分起動の設定と間違えやすい・・)
* 1 * * * echo 'hello'
上記は意図しない設定のことが多いので、注意が必要です。

毎月◯日に起動する
「日」「時」「分」の3箇所を指定すると、月次(Monthly)で起動できます。
# 毎月3日の4:10に起動
10 4 3 * * echo 'hello'

# 毎月3日と13日の、4:10に起動(カンマで複数指定も可)
10 4 3,13 * * echo 'hello'

# 毎月3〜5日の4:10に起動(ハイフンで範囲指定も可)
10 4 3-5 * * echo 'hello'

毎週◯曜日に起動する
「曜日」「時」「分」を指定すると、週次(Weekly)で起動ができます。
曜日には「0:日曜日 〜 6:土曜日」を指定します。
# 毎週月曜日の午前10:00に起動
0 10 * * 1 echo 'hello'

# 毎週月,水曜日の午前10:00に起動(カンマで複数指定も可)
0 10 * * 1,3 echo 'hello'

# 毎週月〜金曜日の午前10:00に起動(ハイフンで範囲指定も可)
0 10 * * 1-5 echo 'hello'

毎年◯月◯日に起動する
年に1度しか動かない処理は少し怖いですが、「月」「日」「時」「分」を指定すると、年次(Yearly)で起動できます。
# 毎年1月3日の10:00に起動
0 10 3 1 * echo 'hello'



起動時間の書き方(応用編)

基本編の記述ができれば、ほとんどの要件に対応できますが、cronでは下記のような設定も可能です。

10分ごとや2時間ごとに起動する
時間指定で「*/10」のような指定をすると、10分毎、2時間毎、1日おき、などの指定が可能です。
# 10分ごとに起動する
*/10 * * * * echo 'hello'

# 2時間ごとに起動する(0時、2時、4時、...)
0 */2 * * * echo 'hello'

# 2時間ごとに起動する(1時、3時、5時、...)
0 1-23/2 * * * echo 'hello'

# 1日おきに起動する
0 0 */2 * * echo 'hello'

月初に起動したい
月次(Monthly)指定で、「1日」を指定すると月初に起動できます。
# 月初の午前2:00に起動
0 2 1 * * echo 'hello'

月末に起動したい
cronでは、月末を指定できません。月末が28日なのか、31日なのか、カレンダーによるからです。月末に処理を起動したい場合、下記のロジックで処理を行います。

28〜31日に処理を起動し、翌日が1日であるかをチェックし、それがTrueの場合には処理を行う。

上記ロジックをcronで記述すると、下記となります。
# 月末の00:00に処理を起動(翌日が1日かをチェックして、trueなら、処理を実行する)
0 0 28-31 * * /usr/bin/test $(date -d '+1 day' +%d) -eq 1 && [実行したいコマンド]
/usr/bin/test」のパスと、「date -d '+1 day' +%d」の書き方は、Linuxの種類により異なる場合があります。動かなかったら調整してください。



最後に

今日はcronのいろいろな書き方をまとめました。cronを使うことは多いですが、僕はなんとなく使っていた派でした。ちゃんと学んでみよう〜と思い、今回のブログを書きました。

最後になりますが本ブログでは、サーバー、Python、フロントエンド、インフラ、PHP、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!



]]>
yoheiMFri, 13 Sep 2019 17:16:25 17SepJST