generated at
kgtt-cliの開発ログ
開発ログを書く意味を参考に、Scrapbox流に合う方式を考える。
CLIでそういう環境を整えるっていうのもいいかもな
---> search

- 17:15


目標
p - 14:30 テストを通す。; 14:21
14:40 commander.jsを使ってCLIを整備していこう。
14:40 commander.jsを使ってCLIを整備していこう。; Commander.jsの仕様を読む。
p-15:00 command.jsを使ってヘルプを出せるようにする。
到達点が曖昧だった。
p- 15:30 全ての機能をasync fucntion化する。
p 15:30 ヘルプを整備する。
p - 15:55
15:30 実際に動くか確かめる。
履修登録してきた(16:50締切)
16:50

20:00 -
pissue 教職他の学年・学科課程に対応できていない
教職他が入力された時とそうでない時で挙動を切り替えよう。
あれ...?切り替わらない...
と思ったけど単純にjsonの方向へ出力してないだけだった.
pissue CSV出力で、列がおかしい。
JSONだとその限りでもない。
ts
const headers = ['曜日', '学年', '学科課程', '時限', '授業コード', '十字', '講義名', '担当者名', '教室'] as const;
この配列通りの出力順になってない。なんでだ
ts
let csv = Object.keys(講義項目群[0]).join(",") + "\n";
headersとは違うものをヘッダ行にしてたわ

16:33 -
pissue 時間割行リストの値が設定されているはずのキーが存在していない
前処理が行われていないことが原因だった。
ただしく置換されるように、CRLF \r\n LF \n を入力した。
文字列リテラルにCRLFとLFの混同問題がまぜこぜにならないように...。
pissue 学年・学科課程に中点の・がありません。:1年
「学年と学科課程」の欄に・がない行があった。
このような行を見つけてもエラーを出さず、学科課程を空白のままにするようにしよう。
pissue Cannot read properties of undefined (reading 'indexOf')
また前処理が正しく行われていないのが原因
春学期を基準にヘッダー置換していたけど、これではだめだ。
先頭N行を置換みたいなやり方の方がいいかもしれない。
(.*\r\n){4} で置き換えるのはどうか...?
CRLFを考慮した置換
一番楽
ExcelのCSV出力の仕様が変わったら死にそう。
だめだった なんでだろう
\r\nが検出されてない...
(.*\n){6} がうまくいく。
ただし、ヘッダが今後変わったらその度に対処しなくちゃならない。
""の内部の文字にマッチさせる方法、正規表現の最適化
最短検索は *? 、なるほど。
/"(.*?\n)*?.*?"/
いや、"以外の文字を全て通せばいいのだから
/"([^"]*\n)*[^"]*"/ とすれば、""の内部の文字にヒットさせられる?
いや、もっと単純化できる。改行も中に入れられると考えれば...
/"([^"]|\n)*"/
いった。
おお〜〜
これを組み込めば...
/(("([^"]|\n)*"|[."]*)\n){4}/
これで、CSV上で先頭4行を捉えることができるぞ!
だめでした。
これってChatGPTに頼んだら書いてくれるか?
^(?:(?:"(?:[^"\n\r]|""|\\\n)*"\n)|(?:[^\n\r]*\n)){3}
任意の3行マッチ
これ?:を取り除いたらうまくうごく?
^(("([^"\n\r]|""|\n)*"\n)|([^\n\r]*\n)){3}
^((("[^"]*")?[^",\n]*)+,?\n){0,3}((("[^"]*")?[^",\n]*)+,?\n)?
> ((("^"*")?^",\n*)+,?\n): CSVファイルの1行にマッチします。このグループには、カンマで区切られた値、またはダブルクォーテーションで囲まれた値が含まれます。ダブルクォーテーションで囲まれた値には、改行文字が含まれることができます。
> ((("^"*")?^",\n*)+,?\n){0,3}: 最初の3行にマッチするように、1行を最大3回繰り返します。
> ((("^"*")?^",\n*)+,?\n)?: 4番目の行にマッチするように、1行を0回または1回繰り返します。
> ^: 文字列の先頭にマッチします。
難読化待ったなし!!正規表現でやるのやめた
先頭から一文字づつ読んでいくか。

15:12 -
全ての機能を関数にした。
リソース読み込みなどの機能も極力index側に分離。
処理本体の依存モジュールが減った。
よし、とりあえず仕様は全部書いたぞ...。
ただ、系列検索時にデータベースファイルとしてJSONしか受け付けないのは不便だ。
CSVでもJSONでも読めるようにしておくか。
や、ちょっとめんどくさい
やめた。
説明文を打ち終わる。
デバッグを始める。

14:28 - 15:12
npm install commander
なんともまあ雰囲気でわかりやすい...。
よし、とりあえずざっくりとした使い方は掴めた。
コードがわかりやすい!
おぉ...ちゃんとヘルプが表示されている。
とりあえず暫定的にタイトルはkgtt(KwaseiGakuin -- TimeTable)で...
...なんかもっといい名前ないか。
略字に母音を加えたくないか...?

- 14:21
学年と学科課程に複数の が含まれていた場合に、正しく学年と学科課程へ分割されない問題を修正
単純にsplitしていたが、そうすると学科課程の区切りで変に分割される。
V は違う文字....??
ターミナル上だと明らかにわかるんだけど、エディタ上だと表示に差がなさすぎる
()と()も違う文字だったりします...?
流石にそんなことはなかった。
単純に全角数字が変換されてなかっただけ。
でも全角()よりも半角()の方が慣れてるからな....
よし!半角に変換しておこう。(あとで恨まれそう)
これのせいで通ってなかった。
いよし!



学んだ
解決
サンドボックス作って実験すると解決が早まるな...。
フルESMに傾倒して実装しようと思う。

21:00 -
問題解決
> To enable this you don’t need to do anything special. Write your test file as an ES module. In Node.js this means either ending the file with a .mjs extension, or, if you want to use the regular .js extension, by adding "type": "module" to your package.json. More information can be found in the Node.js documentation.

moduleResolution: nodenextってなんやねん

現状
esm 形式に則って書くと全て ts-node 上では正しく実行される。
esm 形式に則って書くと全て ts-mocha 上ではエラーが出る。
❯ npx mocha -r ts-node/register src/**.test.ts
TypeError ERR_UNKNOWN_FILE_EXTENSION: Unknown file extension ".ts" for /.../timetable/src/parsetimetable.test.ts
❯ npx ts-node src/**.test.ts
ReferenceError: describe is not defined
うーん
整理
❯ npx ts-node src/parseTimeTable.ts \n Error: Cannot find module './sorting.js'
neat-csvを使うのにESMは必要 (types:"module"で、index.jsがindex.mjsとみなされる)
全てのファイル形式をESM形式にしなければならない
package.json "types":"module"
tsconfig.json "moduleResolution": "nodenext"
---> あるいはdynamic importを使うか
❯ npx ts-node src/parseTimeTable.ts TypeError \n [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/AppleBird/Downloads/timetable/src/parseTimeTable.ts
これnodeに直接tsファイルが渡されてる...!?
nodeはjsしか読めないから、確かにtsがわけわからんと言ってもおかしくはない

19:02 - 20:16
これまでに作った機能はちゃんと動くのか?テストする。
ちょっと外部環境(ファイルなど)が影響しないように分離。
文字列からの入力として純粋にテストできるように修正。
時間割の記述されたcsv文字列をパースする」の参照透過性を確保。
「時間割CSVのパース」に名前変更
pテストを書く。
春期と秋期に対してそれぞれ2行程度を抽出。
それらに対して期待する出力を書く。
あかん、思ったよりめんどくさい
できた!でも合ってるかな...。
テストを通す。
Stucked: TypeError: Unknown file extension ".ts" とは
症状
npx ts-mocha -p tsconfig.json src/**.test.ts を実行する。
parse_timetable.test.ts のテストでそのエラーが出る。
preprocess.test.ts のテストではエラーが出ない
ESMLoaderがスタックトレースに出現している。
--esm オプションをつける...。

前に通したファイルではしっかり実行されている。
[]
句読点「。」って関数名変数名では無効な文字なのか....。

15:47 - 16:57
OpenSiv3D実装会へ参加しながら開発を進める。
OpenAIAPI、思ったより楽に利用できそうだな....。
一瞬開発ログでページ分離してたけどやめた
前処理を挟む
いちいち一時ファイルを作る必要があるのかな...?
APIを覗き見てる限りこれ以外の手段はなさそう...?
いいwrapperがあった。
Promiseベースでcsv_parserが使える。これならコードもわかりやすい。
ただし、csv-parserのAPIの様子と、これがwrapperであることを考慮すると、一度データの内容を書き込んでるんかな...?
コードをみないとわからんね。
cat 2023spring_test.csv | npx csv-parser
秋学期の時間も読み込ませて、タームに対応させる。
TimeTableRowからの講義基本情報の抽出に、タームの情報も渡す。
やった。
改行セルありCSVにcsv-parserくんは耐えられるのか...?
CLIがあったので試してみた。耐えるっぽい!
行内改行は \r\n に置き換えられる。

15:27 - 15:46
通した。


15:22 - 15:27
正規表現の置換で対処できない。
多分必要なさそう。
CSVの書式の中に、セル内改行のルールが含まれている。
もっとも、標準ではなさそうだが。

p 必要な前処理
p これらをバッチ処理にできないだろうか...?appbird
日本語(Windows, DOS) --> utf-8へ変換
Shift-JISではない、ローマ数字が文字化けする。
改行コードCRLFLFの混在の解消
どうやらExcelでcsvによって保存すると
セル中の改行はLF
csvとしての改行はCRLFで表されるらしい。
適宜LFの改行を消す必要がある。
先頭2行を消す。
時間割のタイトル行にあたる。
こうしないとcsv-parserに正しく表が読み込まれない。
3行目を削除する。
この表は3行目と4行目にヘッダが分布している。
しかし、解析に3行目はあまり必要ないので解析から飛ばす。
4行目のヘッダ名が一意になるように修正する。
line4.csv
,,授業コード,講義名,担当者名,,,授業コード,講義名,担当者名,,授業コード,講義名,担当者名,,授業コード,講義名,担当者名,,授業コード,講義名,担当者名,
しかし、4行目には同一ヘッダ名が含まれる。
csv-parserは同一ヘッダ名が見受けられる場合に、それらを集約してしまう
それでは困るので、それぞれに時限情報を付記していく。
さらに、時限(1列目), 学年学科課程(2列目), 教室(担当者名の次の列)の列に当たるヘッダ名が空白になっている
このままではデータを解析する際に面倒臭い。
適当にヘッダ名を補っておく。
要するに、4行目は以下の通り置き換えられたらいい
csv
曜日,学年・学科課程,1授業コード,1十字,1講義名,1担当者名,1教室,,2授業コード,2十字,2講義名,2担当者名,2教室,3授業コード,3十字,3講義名,3担当者名,3教室,4授業コード,4十字,4講義名,4担当者名,4教室,5授業コード,5十字,5講義名,5担当者名,5教室

pというわけで、JSONとCSVに変換してみる。
次の形式に変換する。
typescript
{ "学年": string, "学科課程": string, "曜日": string, "時限": string, "授業コード": string, "十字": string, "講義名": string, "担当者名": string, "教室": string }[]
できた。
#TODO あとでgistに公開する



pサンプル通りに実行してみる。
ただし、requireを使わないようにしている。
csv-parserはdefault importで使用する。
コマンドライン引数としてcsvのパスを受け取るようにしている。
実行形態
tsc && node index.js timetable.csv
npm scriptsにこれを登録しておけば、vscode側のデバッガーを利用することができて便利である。
スタックトレース変数の中身がチラ見できる。
ObjectType はキーが文字列、値が文字列であるようなオブジェクトである。
ts
import csv from "csv-parser"; import {createReadStream} from "fs"; import { argv } from "process"; type ObjectType = {[key:string]:string}; const result:ObjectType[] = []; const param = argv[2]; console.log(param) createReadStream(param) .pipe(csv()) .on('data', (data:ObjectType) => result.push(data)) .on('end', () => console.log(result));

以下のような配列型に沿ったデータを得ることができる。
リダイレクトを使えば結果をじっくり見られる。
tsc && node index.js timetable.csv > out.txt
実際の中身は伏せる。
ts
{ '曜日': string, '学年・学科課程': string, '1授業コード': string,'1十字': string,'1講義名': string,'1担当者名': string,'1教室': string, '': string, '2授業コード': string,'2十字': string,'2講義名': string,'2担当者名': string,'2教室': string, '3授業コード': string,'3十字': string,'3講義名': string,'3担当者名': string,'3教室': string, '4授業コード': string,'4十字': string,'4講義名': string,'4担当者名': string,'4教室': string, '5授業コード': string,'5十字': string,'5講義名': string,'5担当者名': string,'5教室': string }[]

p コマンドライン引数に渡されたデータを使えるように。
process.argvを使えばいい。