kgtt-cliの開発ログ
CLIでそういう環境を整えるっていうのもいいかもな
- 17:15
目標

- 14:30 テストを通す。; 14:21

-15:00 command.jsを使ってヘルプを出せるようにする。
到達点が曖昧だった。

- 15:30 全ての機能を
async fucntion化する。
15:30 ヘルプを整備する。
- 15:55
15:30 実際に動くか確かめる。
履修登録してきた(16:50締切)
16:50
20:00 -

issue 教職他の学年・学科課程に対応できていない
教職他が入力された時とそうでない時で挙動を切り替えよう。
あれ...?切り替わらない...
と思ったけど単純にjsonの方向へ出力してないだけだった.

issue CSV出力で、列がおかしい。
JSONだとその限りでもない。
tsconst headers = ['曜日', '学年', '学科課程', '時限', '授業コード', '十字', '講義名', '担当者名', '教室'] as const;
この配列通りの出力順になってない。なんでだ
tslet csv = Object.keys(講義項目群[0]).join(",") + "\n";
headersとは違うものをヘッダ行にしてたわ
16:33 -

issue 時間割行リストの値が設定されているはずのキーが存在していない
前処理が行われていないことが原因だった。
ただしく置換されるように、
CRLF \r\n
と
LF \n
を入力した。
文字列リテラルにCRLFとLFの混同問題がまぜこぜにならないように...。

issue
学年・学科課程に中点の・がありません。:1年
「学年と学科課程」の欄に・がない行があった。
このような行を見つけてもエラーを出さず、学科課程を空白のままにするようにしよう。

issue
Cannot read properties of undefined (reading 'indexOf')
また前処理が正しく行われていないのが原因
春学期を基準にヘッダー置換していたけど、これではだめだ。
先頭N行を置換みたいなやり方の方がいいかもしれない。
(.*\r\n){4}
で置き換えるのはどうか...?
一番楽
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
と Ⅴ
は違う文字....??
ターミナル上だと明らかにわかるんだけど、エディタ上だと表示に差がなさすぎる
()と()も違う文字だったりします...?
流石にそんなことはなかった。
単純に全角数字が変換されてなかっただけ。
でも全角()よりも半角()の方が慣れてるからな....
よし!半角に変換しておこう。(あとで恨まれそう)
これのせいで通ってなかった。
いよし!
学んだ
解決
サンドボックス作って実験すると解決が早まるな...。
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.
現状
esm
形式に則って書くと全て ts-node
上では正しく実行される。
esm
形式に則って書くと全て ts-mocha
上ではエラーが出る。
❯ npx mocha -r ts-node/register src/**.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形式にしなければならない
---> あるいは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のパース」に名前変更

テストを書く。
春期と秋期に対してそれぞれ2行程度を抽出。
それらに対して期待する出力を書く。
あかん、思ったよりめんどくさい
できた!でも合ってるかな...。
テストを通す。
Stucked: TypeError: Unknown file extension ".ts"
とは
症状
npx ts-mocha -p tsconfig.json src/**.test.ts
を実行する。
parse_timetable.test.ts
のテストでそのエラーが出る。
preprocess.test.ts
のテストではエラーが出ない
--esm
オプションをつける...。
前に通したファイルではしっかり実行されている。
[]
句読点「。」って関数名変数名では無効な文字なのか....。
15:47 - 16:57
一瞬開発ログでページ分離してたけどやめた
前処理を挟む
いちいち一時ファイルを作る必要があるのかな...?
APIを覗き見てる限りこれ以外の手段はなさそう...?
ただし、csv-parserのAPIの様子と、これがwrapperであることを考慮すると、一度データの内容を書き込んでるんかな...?
コードをみないとわからんね。
cat 2023spring_test.csv | npx csv-parser
秋学期の時間も読み込ませて、タームに対応させる。
TimeTableRowからの講義基本情報の抽出に、タームの情報も渡す。
やった。
行内改行は \r\n
に置き換えられる。
15:27 - 15:46
通した。
15:22 - 15:27
多分必要なさそう。
CSVの書式の中に、セル内改行のルールが含まれている。
もっとも、標準ではなさそうだが。

必要な前処理
日本語(Windows, DOS) --> utf-8へ
変換どうやらExcelでcsvによって保存すると
csvとしての改行はCRLFで表されるらしい。
適宜LFの改行を消す必要がある。
時間割のタイトル行にあたる。
3行目を削除する。
この表は3行目と4行目にヘッダが分布している。
しかし、解析に3行目はあまり必要ないので解析から飛ばす。
4行目のヘッダ名が一意になるように修正する。
line4.csv,,授業コード,講義名,担当者名,,,授業コード,講義名,担当者名,,授業コード,講義名,担当者名,,授業コード,講義名,担当者名,,授業コード,講義名,担当者名,
しかし、4行目には同一ヘッダ名が含まれる。
それでは困るので、それぞれに
時限の
情報を付記していく。
このままではデータを解析する際に面倒臭い。
適当にヘッダ名を補っておく。
要するに、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教室

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

サンプル通りに実行してみる。
実行形態
tsc && node index.js timetable.csv
型
ObjectType
はキーが文字列、値が文字列であるような
オブジェクトである。
tsimport 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
}[]