From d0f958b2ad5ae808ceaa5538303766e86ba93ebf Mon Sep 17 00:00:00 2001 From: swawa-yu Date: Tue, 26 Dec 2023 03:35:00 +0900 Subject: [PATCH] =?UTF-8?q?=E9=96=8B=E8=A8=AD=E6=9C=9F=E3=82=84=E6=8E=88?= =?UTF-8?q?=E6=A5=AD=E6=99=82=E9=96=93=E3=81=AB=E9=96=A2=E3=81=99=E3=82=8B?= =?UTF-8?q?=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/subject/index.ts | 28 ++++-- src/subject/parser.ts | 127 +++++++++++++++++------- src/table-view/SubjectUnitComponent.tsx | 44 +++++--- src/table-view/SyllabusTable.tsx | 2 +- 4 files changed, 141 insertions(+), 60 deletions(-) diff --git a/src/subject/index.ts b/src/subject/index.ts index 88f0230..25d053b 100644 --- a/src/subject/index.ts +++ b/src/subject/index.ts @@ -1,17 +1,25 @@ // import { Periods } from './period'; +// 全授業の主要情報の辞書 import subjectData from '../../data/subject-maininfo.json' -export interface kaisetsuki { +export interface Kaisetsuki { rishuNenji: number semester: Semester jikiKubun: JikiKubun } -export interface schedule { - jikiKubun: JikiKubun - jigen: string // TODO 集中 とかある どうにかしたい - room: string +// TODO 命名が最悪すぎる 「jigen」ってなんだ +export interface Jigen { + youbi: "月" | "火" | "水" | "木" | "金" | "土" | "解析エラー" + jigenRange: [begin: number, last: number] | "解析エラー" + komaRange: [begin: number, last: number] | "解析エラー" +} + +export interface Schedule { + jikiKubun: JikiKubun // 1ターム、2ターム、3ターム、4ターム、セメスター(前期)、セメスター(後期)、ターム外(前期)、ターム外(後期)、年度、通年、集中 + jigen: Jigen | undefined // 集中講義の場合はundefined + room: string // 何も書かれていない場合は空文字列 } // TODO 「解析エラー」としているが、他に適切な書き方がありそう @@ -48,13 +56,13 @@ export type Subject = { } export type SubjectMap = { [subjectCode: string]: Subject } -// export const subjectMap: SubjectMap = {}; export const subjectMap: SubjectMap = {}; export const subjectCodeList = Object.keys(subjectMap); // 何を表示するかここで決める // export const propertyToShowList = ["講義コード", "開講部局", "開設期", "授業科目名", "単位", "教科書・参考書等"] +// ※今は便宜的にすべてのプロパティを表示するためにinitializeSubject()内で初期化している。 export const propertyToShowList: string[] = [] export const subjectProperties: string[] = [] @@ -63,11 +71,9 @@ export const subjectProperties: string[] = [] // TODO 教員のリサーチマップ https://researchmap.jp/researchers?q=名字+名前 // TODO お気に入り教員 // TODO 講義名をマウスホバーで講義の詳細を表示 -// TODO setTimeout()ってなに +// TODO setTimeout()ってなに, async await って使ったほうがいいの? -// TODO async await って使ったほうがいいの? export const initializeSubject = () => { - // export const initializeSubject = async () => { // 表示する授業を記憶しておく配列とかを空にする Object.keys(subjectMap).forEach((key) => { @@ -78,13 +84,15 @@ export const initializeSubject = () => { // 授業データの読み込み const subjectMap_ = subjectData as unknown as SubjectMap; - // const subjectMap_ = (await import('../../subjects.json')) as unknown as SubjectMap; // 表示する授業を記憶しておく配列とかに値を設定する Object.entries(subjectMap_).forEach(([key, value]) => { subjectMap[key] = value subjectCodeList.push(key) }) + + // 便宜的に、すべてのプロパティを表示することにしている。そのためのループ。本来は変数定義時に決定する。 + // propertyToShowList = Object.keys(subjectMap["10000100"]); Object.keys(subjectMap["10000100"]).forEach((value) => { // if (propertyToShowList.length < 27) propertyToShowList.push(value) diff --git a/src/subject/parser.ts b/src/subject/parser.ts index dc43c11..87e5821 100644 --- a/src/subject/parser.ts +++ b/src/subject/parser.ts @@ -1,75 +1,134 @@ import { - schedule, kaisetsuki, + Schedule, Kaisetsuki, // Semester, jikiKubuns, // JikiKubun, - semesters + semesters, + Jigen, + JikiKubun } from "."; +// TODO: semester, jikikubunはKaisetsukiとScheduleで被っている + /** * - * @param s - * @returns schedule[] + * @param s: string + * @returns Kaisetsuki */ -export function parseKaisetsuki(s: string): kaisetsuki { - // TODO 開口部局が大学院かどうかは履修年次に影響する +export function parseKaisetsuki(s: string): Kaisetsuki { + // TODO 開口部局が大学院かどうかが履修年次に影響する + // 1年次生 前期 2ターム // 1年次生 前期 集中 + // 1年次生 後期 セメスター(後期) // 空白によって3つに区切られている // TODO(それ以外のケースはないか) - // n年次生 (n=1~5) + // n (n=1~5) ※修士博士をどう扱うか(そのための実装はまだできていないので、修士1年は5年じゃなくて1年になる) // 前期 | 後期 // 1ターム | 2ターム | 3ターム | 4ターム | セメスター(前期) | セメスター(後期) | 集中 | 年度 | 通年 - // TODO それ以外のケースがないか const splitted = s.split(' '); - // let semester: Semester - // if (splitted[1] == "前期") { - // semester = "前期" - // } else if (splitted[1] == "後期") { - // semester = "後期" - // } else { - // semester = "解析エラー" - // } - - // TODO ゴリ押し(下に同じ) return { rishuNenji: parseInt(splitted[0][0]), - semester: semesters.some((v) => v === (splitted[1])) ? semesters.filter((v) => v === splitted[1])[0] : "解析エラー", - // semester: semester, - jikiKubun: jikiKubuns.some((v) => v === (splitted[2])) ? jikiKubuns.filter((v) => v === splitted[2])[0] : "解析エラー" + semester: semesters.some((v) => v === (splitted[1])) ? splitted[1] as Kaisetsuki['semester'] : "解析エラー", + jikiKubun: jikiKubuns.some((v) => v === (splitted[2])) ? splitted[2] as Kaisetsuki['jikiKubun'] : "解析エラー" }; } +const jikiKubunMap: { [key: string]: JikiKubun } = { + "(1T)": "1ターム", + "(2T)": "2ターム", + "(3T)": "3ターム", + "(4T)": "4ターム", + "(前)": "セメスター(前期)", + "(後)": "セメスター(後期)", + "(集)": "集中", + "(年)": "年度", + "(通)": "通年", +} + +/** + * + * @param s: string + * @returns Schedule[] + */ export function parseSchedule(s: string) { + // 例---------------------------------------- + // (2T) 火7-8, 金7-8:先405N → (2T) 火7-8:先405N, (2T) 金7-8:先405N // (1T) 木1-2:オンライン, (1T) 木3-4:霞R402講義室 - // 1年次生 前期 2ターム, (2T) 火7-8,金7-8:先405N + // (4T) 集中:担当教員の指定による + // (前) 木7-8:理E102 + // (前) 金7-8:北体育館,教K102 → そのままでOK + // ------------------------------------------ + + // 検索するとき、部屋は別にそんなに重要ではない + // ただし、空き部屋検索のときは重要 // 空白で区切ったときの長さが2の時は、その後":"でsplitすれば曜日時限と教室に分かれる // 時間だけで部屋が書かれていないことがある - // 時間がなく部屋だけ書かれているなど、その他のパターンはある? → ない + // 時間がなく部屋だけ書かれているなど、その他のパターンはある? → ない(検証済み) + + let schedules: Schedule[] = [] - let schedules: schedule[] = [] + + + // シンプルなパターンの実装 try { + const splittedBySpace = s.split(' '); + const splittedByColon = splittedBySpace[1].split(':'); + + // 辞書の中にない場合は解析エラー + const jikiKubun: Schedule['jikiKubun'] = jikiKubunMap[splittedBySpace[0]] ? jikiKubunMap[splittedBySpace[0]] : "解析エラー"; + + jikiKubunMap[splittedBySpace[0]]; + + const jigenString = splittedByColon[0]; // 金3-6 (難しいやつだと火7-8,金7-8もある) + // jigenStringの0文字目は曜日 + // jigenStringの1文字目以降をsplit('-')してさらに各要素をintに変換したもの + const jigenNums = jigenString.slice(1).split('-').map((v) => parseInt(v)); - const splitted = s.split(' ') - // 1スケジュール単位を2つ以上繰り返すときに","がつくので、取り除く - for (let i = 0; i < splitted.length / 2; i++) { - const jigenAndRoom = splitted[i * 2].split(":"); - // TODO ゴリ押しすぎる - const jiki: schedule['jikiKubun'] = jikiKubuns.some((v) => v === (splitted[i * 2])) ? jikiKubuns.filter((v) => v === splitted[i * 2])[0] : "解析エラー"; - const jigen: schedule['jigen'] = jigenAndRoom[0] - const room: schedule['room'] = jigenAndRoom.length == 2 ? jigenAndRoom[1] : "" - schedules.push({ jikiKubun: jiki, jigen: jigen, room: room }) + const jigen: Schedule["jigen"] = jigenString[0] === "集" ? undefined : { + youbi: jigenString[0] as Jigen['youbi'], + jigenRange: [jigenNums[0], jigenNums[jigenNums.length - 1]] as Jigen['jigenRange'], + komaRange: [(jigenNums[0] + 1) / 2 | 0, (jigenNums[jigenNums.length - 1] + 1) / 2 | 0] as Jigen['komaRange'] } + + const room = splittedByColon[1]; + + schedules.push({ jikiKubun: jikiKubun, jigen: jigen, room: room }) } catch (e: unknown) { - schedules.push({ jikiKubun: "解析エラー", jigen: "解析エラー", room: "解析エラー" }) + schedules.push({ jikiKubun: "解析エラー", jigen: { youbi: "解析エラー", jigenRange: "解析エラー", komaRange: "解析エラー" }, room: "解析エラー" }) return schedules; } + + // 複雑なパターンの実装 + // try { + // const hiphenCount = s.split('-').length - 1; + // const colonCount = s.split(':').length - 1; + // const splitted = s.split(' ') + // // 1スケジュール単位を2つ以上繰り返すときに","がつくので、取り除く + // for (let i = 0; i < splitted.length / 2; i++) { + // const jigenAndRoom = splitted[i * 2].split(":"); + + // // TODO ゴリ押しすぎる + // const jiki: Schedule['jikiKubun'] = jikiKubuns.some((v) => v === (splitted[i * 2])) ? + // jikiKubuns.filter((v) => v === splitted[i * 2])[0] : + // "解析エラー"; + // const jigen: Schedule["jigen"] = { youbi: "解析エラー", jigenRange: "解析エラー", komaRange: "解析エラー" } + // const room: Schedule['room'] = jigenAndRoom.length == 2 ? + // jigenAndRoom[1] : + // "" + // schedules.push({ jikiKubun: jiki, jigen: jigen, room: room }) + // } + // } catch (e: unknown) { + // schedules.push({ jikiKubun: "解析エラー", jigen: { youbi: "解析エラー", jigenRange: "解析エラー", komaRange: "解析エラー" }, room: "解析エラー" }) + // return schedules; + // } + return schedules; } diff --git a/src/table-view/SubjectUnitComponent.tsx b/src/table-view/SubjectUnitComponent.tsx index de076f8..0c10a4e 100644 --- a/src/table-view/SubjectUnitComponent.tsx +++ b/src/table-view/SubjectUnitComponent.tsx @@ -6,11 +6,13 @@ import React from 'react'; // } from './'; import './SubjectUnitComponent.css' +import { parseKaisetsuki, parseSchedule } from '../subject/parser' +import { Subject } from '../subject'; -type LectureUnitProps = { +type SubjectUnitComponentProps = { // 必要なプロパティを定義 - subjectData: any; // 適切な型に変更してください + subject: Subject; // 適切な型に変更してください }; @@ -18,23 +20,35 @@ type LectureUnitProps = { -const SubjectUnitComponent: React.FC = ({ subjectData }) => { +const SubjectUnitComponent: React.FC = ({ subject: subject }) => { + const schedules = parseSchedule(subject["曜日・時限・講義室"]); + const kaisetsuki = parseKaisetsuki(subject["開設期"]); + return (
-
{subjectData["講義コード"]}
-
{subjectData["授業科目名"]}
-
{subjectData["担当教員名"]}
+
{subject["講義コード"]}
+
{subject["授業科目名"]}
+
{subject["担当教員名"]}
-
{subjectData["開設期"]}
-
{subjectData["開講キャンパス"]}
-
{subjectData["対象学生"]}
-
{subjectData["使用言語"]}
+
{subject["開設期"]}
+
{subject["曜日・時限・講義室"]}
+ {/*
セメスター:{kaisetsuki.semester}
*/} + {/*
履修年次:{kaisetsuki.rishuNenji}
+
時期区分(開設期):{kaisetsuki.jikiKubun}
+
時期区分(schedules):{schedules[0].jikiKubun}
*/} + {/*
曜日:{schedules[0].jigen?.youbi[0]}
+
時限Range:{schedules[0].jigen?.jigenRange[0]}-{schedules[0].jigen?.jigenRange[1]}
+
コマRange:{schedules[0].jigen?.komaRange[0]}-{schedules[0].jigen?.komaRange[1]}
*/} + {/*
講義室:{schedules[0].room}
*/} +
{subject["開講キャンパス"]}
+ {/*
対象学生:{subject["対象学生"]}
*/} + {/*
{subject["使用言語"]}
*/}
-
{subjectData["授業の目標・概要等"]}
-
{subjectData["メッセージ"]}
+
{subject["授業の目標・概要等"]}
+
{subject["メッセージ"]}
); @@ -43,9 +57,9 @@ const SubjectUnitComponent: React.FC = ({ subjectData }) => { return (
{/* ここに授業の情報を表示するコードを書きます */} -

{subjectData["授業科目名"]}

-

{subjectData["開講部局"]}

-

{subjectData["科目区分"]}

+

{subject["授業科目名"]}

+

{subject["開講部局"]}

+

{subject["科目区分"]}

{/* 他の必要な情報を追加 */}
); diff --git a/src/table-view/SyllabusTable.tsx b/src/table-view/SyllabusTable.tsx index b1ec9d1..d415073 100644 --- a/src/table-view/SyllabusTable.tsx +++ b/src/table-view/SyllabusTable.tsx @@ -29,7 +29,7 @@ function SyllabusTable({ searchOptions }: SyllabusTableProps) { {/* LectureUnit コンポーネントを使用して授業を表示 */}
{data.map((subject, index) => ( - + ))}