【SQL】txtからcsvを生成する

どうも、ねこきち(@nekokichi1_yos2)です。

 

SQLにデータを登録する際、予めcsvを用意すれば、簡単に登録できます。

 

ですが、テキストファイルからcsvを生成すれば、もっと手軽です。

 

今回は、テキストファイルをcsvに変換する方法を備忘録として書きます。

 

 

実行環境

・MacBookAir(M1 2020)
MySQL  5.7.37

 

解説

テキストファイルを用意

例として、下記内容のtxtを用意。

# データ.txt 

1,A,99 2,B,94 3,C,90 4,D,87 5,E,86

 

拡張子をcsvに変換

MacのNumbersで表示。

 

※補足:SQLに登録

(データベース、テーブルの登録は省略します)

 

下記コマンドでSQLにcsvを登録。

mysql> load data local infile "csvのパス" into table テーブル名 fields terminated by ',';

 

下記の通りに出力。

+--------------+--------+--------+
| 学籍番号     | 名前   | 点数   |
+--------------+--------+--------+
|            1 | A      |     99 |
|            2 | B      |     94 |
|            3 | C      |     90 |
|            4 | D      |     87 |
|            5 | E      |     86 |
+--------------+--------+--------+

 

参考

blog.chatlune.jp

指定ファイルの更新時に通知してくれるスクリプト【シェルスクリプト】

どうも、ねこきち(@nekokichi1_yos2)です。

 

とある企業のコーディング課題で、ファイルを監視する問題が出て、シェルスクリプトで実装しました。

 

備忘録として投稿します。

 

動作環境

  • MacBookAir(M1 2020)
  • macOS Monterey 12.1
  • /bin/zsh

 

仕組み

監視対象のファイルパスを取得

監視したいファイルのパスを用意。

シェルの実行ファイル(.sh)と同じ箇所なら、ファイル名だけで良い。

filePath="xxxx/yyyy/zzzz"

 

変更日時を取得

ls -l -T、で対象ファイルの属性情報を取得。

-rw-r--r--@ 1 ユーザ名  staff  99  4 10 12:08:50 2022 ファイル名
last=`ls -l -T $filePath | awk '{print $6"月"$7"日"$8}'`

 

監視開始

while文で実行し続け、1秒度に監視。

while true; do
        sleep 1
... done

 

最新の変更日時を取得

1秒後の更新日時を取得。

current=`ls -l -T $filePath | awk '{print $6"月"$7"日"$8}'`

 

変更日時、現在の変更日時を比較

もし1秒前と1秒後でタイムスタンプが違えば、変更がされているので、処理を実行。

今回だと、"updated: $current"、と出力

if [[ $last != $current ]] ; then
        echo "updated: $current"
... fi

 

変更日時を更新

変更されるたびに最新の更新日時を取得

last=$current

 

実行結果

xxxx@xxxx ディレクトリ % ./test.sh

updated: 4月10日11:42:53

updated: 4月10日11:44:51

 

ソースコード

filePath="ファイルのパス"
last=`ls -l -T $filePath | awk '{print $6"月"$7"日"$8}'`
while true; do
        sleep 1
        current=`ls -l -T $filePath | awk '{print $6"月"$7"日"$8}'`
        if [[ $last != $current ]] ; then
                echo "updated: $current"
                last=$current
        fi
done

 

参考

qiita.com

mizti.hatenablog.com

qiita.com

atmarkit.itmedia.co.jp

ritchiekotzen.hatenablog.com

【サクメモ】進捗状況ver0.02:コーディング開始

どうも、ねこきち(@nekokichi1_yos2)です。

 

理由は、良いアプリを作るために何をすべきかを考えてしまうから、です。

 

下記を参考に、プロトタイピングツールでアプリの完成図を作ろうとしました。

zenn.dev

 

しかし、

  • デザインの経験が0
  • 0からデザインを生み出す経験が0
  • そもそも、アプリの画面が思いつかない
  • 紙にデザインを書くのが面倒

等の理由で、何もしない日々が続いていました。

 

そこで、

  • 個人開発に不可欠
  • 今すぐに取り組める
  • モチベーションが湧く

に当てはまることを考えた結果、コーディングが浮かびました。

 

 

デザインはハードルが高くて苦痛な作業

f:id:nekokichi_yos2:20211231213214p:plain

僕にとってデザインは、壁のようにそびえ立つ存在です。

 

何から始めればいいか、どんな手段で実行するのか、わからないことだらけです。

 

「じゃあ、デザインを学べばいいじゃん」と言われるかもしれません。

 

しかし、僕にとって重要なのは、デザインは進歩を認識しづらい点です。

 

昔、iPadとApplePencilでイラストを模写してた時期がありました。

 

個人開発で悩むのが、最初に何をするか、です。

 

好きな絵を自分の手で描くのは良い気分でした。

 

ですが、あれだけ集中して線を描いて色を塗ったのに、完成したのは1枚の絵。

 

今まで費やした努力の過程は、1枚の絵を見ても実感できません。

 

デザインは、完成するまでの過程に意味がなく、完成して絵は意味や形を宿す。

 

つまり、途中で達成感を味わいづらく、モチベーションが湧かないのです。

 

コーディングは前に進みやすい

f:id:nekokichi_yos2:20211231213210p:plain

コードを書いていると、目的地へ前進していることを実感します。

 

どんなに簡単な処理でも、1つの成果物です。

 

例えば、Swiftで数字を計算する処理を書き、Xcodeのシミュレータで処理が正常に動くかを確認、します。

 

正常に動けば、

  • コードを処理という形に完成させた
  • 自分が思いついたコードは正しい
  • 目的の処理を実現できた

を実感します。

 

もし個人開発ならば、上記を何度も経験できるので、モチベーションを維持できます。

 

つまり、コーディングは好きなのでハードルが低く、小さな達成感を味わいやすいから継続しやすいのです。

 

まとめ:できることは最善の行動


小さなことでもいいから、行動し続けることは大切です。

 

行動した結果を得られれば、達成感を味わい、次の行動へのモチベーションにつながります。

 

個人開発は1人で開発を行うので、途中で投げ出したくなる時が何度もあります。

 

頭にアイデアが思い浮かんでも、実行に移せなければ、何の意味もありません。

 

成果は、何もしなければ生まれません。

 

結局、遠回りでもコツコツと続けられる人が得をする気がします。

【Swift】TextViewで選択した部分の文字列を取得

実現したいこと

  • 先頭~途中/末尾までの文字を取得
  • 途中~末尾までの文字を取得
  • 途中~途中までの文字を取得

仕組み

  1. textViewの文字列を選択
  2. 選択した文字列の開始位置、長さを取得
  3. カーソルが1文字以上を選択してるかを条件分岐
  4. 選択した文字列の開始位置、終了位置を取得
  5. 部分文字列を取得

textViewの文字列を選択

f:id:nekokichi_yos2:20211231210431p:plain

選択した文字列の開始位置、長さを取得

// 開始位置
let location = textView.selectedRange.location
// 長さ
let length = textView.selectedRange.length

文字列の取得に必要。

カーソルが1文字以上を選択してるかを条件分岐

if length <= 0 {
    return
} else {
        // 文字列を取得する処理
}

文字選択の際に表示されるカーソルには、何も選択していない下記の状態が存在する。

f:id:nekokichi_yos2:20211231210435p:plain

もし条件分岐をせずに文字列を取得しようとしたら、下記のエラーが発生。

Thread 1: Fatal error: String index is out of bounds

エラー箇所は文字列を取得する下記のコード。

(原因:文字列が選択されていない → locationとlengthが0 → offsetByが-1)

let endIndex = textView.text.index(strIndex,
                     offsetBy: location+length-1, limitedBy: textView.text.endIndex)

上記のエラーを回避するため、

  • カーソルが文字列を選択
  • カーソルが文字列を選択してない

場合で処理を分岐させた。

選択した文字列の開始位置、終了位置を取得

// strIndex:0番目(Index型の0)
let strIndex = textView.text.startIndex
// Index型の開始位置、終了位置
guard let startIndex = textView.text.index(strIndex,
                     offsetBy: location, limitedBy: textView.text.endIndex),
            let endIndex = textView.text.index(strIndex,
                     offsetBy: location+length-1, limitedBy: textView.text.endIndex) else {
    return
}

仕組みを例えると、

  1. String型“123456”がある
  2. “45”を選択
  3. location = 3, length = 2
  4. startIndex = 3, endIndex = 4

startIndex, endIndexはIndex型。

f:id:nekokichi_yos2:20211231210438p:plainAppleのドキュメントより)

Index型とは、文字の場所を示す値。

printで出力すると、不規則な数字が並ぶので、中身は気にしなくていい。

print(startIndex) // Index(_rawBits: 131329)

部分文字列を取得

textView.textの要素(文字)を、Index型の変数(startIndex, endIndex)を使い、範囲で指定。

print(String(textView.text[startIndex...endIndex])) // 選択した文字列
print(type(of: textView.text[startIndex...endIndex])) // SubString

仕組みを例えると、

  1. 変数text = “123456”がある
  2. “45”を選択
  3. location = 3, length = 2
  4. startIndex = 3, endIndex = 4
  5. text[startIndex...endIndex] = “45”

startIndexとendIndexでどの範囲の文字列を取得するかを指定している。

Appleのドキュメント、SubStringはStringを分割したもの。

そのままでもprint()で出力はできても、Labelのテキストなどに代入するなら、String型にキャストする必要がある。

(でないと、下記のエラーが出る) ↓

Subscript 'subscript(_:)' requires the types 'String.Index' and 'Int' be equivalent

ストーリーボード

f:id:nekokichi_yos2:20211231210428p:plain

ソースコード

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var selectedString: UILabel!
    @IBOutlet weak var textView: UITextView!    

    override func viewDidLoad() {
        super.viewDidLoad()
        textView.delegate = self
    }
}

extension ViewController: UITextViewDelegate {
    // textViewDidChangeSelection:textViewの文字が選択されたら処理
    func textViewDidChangeSelection(_ textView: UITextView) {
        let location = textView.selectedRange.location
        let length = textView.selectedRange.length
        if length <= 0 {
        selectedString.text?.removeAll()
            return
        } else {
            let strIndex = textView.text.startIndex
            guard let startIndex = textView.text.index(strIndex, 
                                            offsetBy: location, limitedBy: textView.text.endIndex),
                  let endIndex = textView.text.index(strIndex, 
                                            offsetBy: location+length-1, limitedBy: textView.text.endIndex) else {
                return
            }
        selectedString.text = String(textView.text[startIndex...endIndex])
        }
    }
}

参考

developer.apple.com

softmoco.com

kimagureneet.hatenablog.com