*/ public function getIgnoredList(): array { $path = "{$this->getParameter('kernel.project_dir')}/data/ignored.list"; $ret = []; $file = fopen($path, 'r'); while (($kanji = fgets($file)) !== false) { $kanji = mb_trim($kanji); $ret[$kanji] = ''; if (mb_strlen($kanji) !== 1) throw new \Exception(sprintf( 'Kanji expected, got "%s"', $kanji, )); while (($explanation = fgets($file)) !== false) { if ($explanation === "\n") continue 2; $ret[$kanji] .= $explanation; } $ret[$kanji] = mb_rtrim($ret[$kanji]); } return $ret; } /** @return array> */ private function getCharInfo(bool $force = false): array { $cacheFile = "$this->varBasepath/charlist.php"; if (!$force and file_exists($cacheFile)) return require $cacheFile; $ret = []; $lists = [ 'sn' => $this->anki->getKnownSnKanjiCounts(), 'sln' => $this->anki->getKnownSlnKanjiCounts(), 'unicode' => $this->anki->getUnicodeKanji(), 'ignored' => $this->getIgnoredList(), ]; // @formatter:off $storedLists = [ 'taiwan', 'bushu', 'kyoyou', 'kyuujitai', 'kanken', 'hsk', 'zhcn', 'jimaku', 'ebook', ]; // @formatter:on foreach ($storedLists as $storedName) { $storedList = $this->charList->getList($storedName); // Simple list if (key_exists('chars', $storedList)) { $lists[$storedName] = $storedList['chars']; } else { foreach ($storedList['sublists'] as $subname => $sublist) { $lists["$storedName-$subname"] = $sublist['chars']; } } } foreach ($lists as $listName => $list) { foreach (array_keys($list) as $char) { $ret[$char] ??= []; $ret[$char][$listName] = 0; } } file_put_contents($cacheFile, 'getCharInfo(force: $request->isNoCache()); $completedRows = []; $completedFlag = true; $chars = []; foreach (range(intval("{$start}0", 16), intval("{$end}f", 16)) as $codepoint) { $charStr = mb_chr($codepoint, 'UTF-8'); if ( !key_exists('ignored', $charInfo[$charStr] ?? ['ignored' => 0]) and !key_exists('unicode', $charInfo[$charStr] ?? []) ) { $completedFlag = false; } if (($codepoint + 1) % 0x10 === 0) { if ($completedFlag === true) $completedRows[] = dechex($codepoint - 0xf); $completedFlag = true; } $chars[] = [ 'str' => $charStr, 'codepoint' => dechex($codepoint), 'lists' => $charInfo[$charStr] ?? [], ]; } return $this->render(self::tmpl('grid'), [ 'characters' => $chars, 'completed' => $completedRows, ]); } #[Route('/{codepoint}/register', 'register', methods: 'GET')] public function register(string $codepoint): Response { // Properly check it's valid (make a util?) $charStr = mb_chr(Number::hexint($codepoint), 'UTF-8'); $note = UnicodeNote::fromCharacter($charStr); $terms = $this->anki->searchTerms($charStr); $note->setTerms($terms); $this->anki->addNote($note, UnicodeNote::DECK); return new Response(); } #[Route('view', 'view', methods: 'GET')] public function view(#[MapQueryParameter] string $char): Response { $charStr = ctype_xdigit($char) ? Number::parseCodepoint($char) : $char; $codepoint = ctype_xdigit($char) ? $char : dechex(mb_ord($char)); $charInfo = $this->getCharInfo()[$charStr] ?? []; //$listTitles = $this->charList->getTitles(); $jiten = json_decode(file_get_contents( "{$this->getParameter('kernel.project_dir')}/data/kanken-links.json", ), true); $terms = $this->anki->searchTerms($charStr); $ebookRef = require "$this->varBasepath/ebook-ref.php"; return $this->render(self::tmpl('view'), [ 'ignored_text' => $this->getIgnoredList()[$charStr] ?? null, 'char' => $charStr, 'codepoint' => $codepoint, 'info' => $charInfo, 'terms' => $terms, 'ref' => $ebookRef[$charStr] ?? [], 'jiten_href' => key_exists($charStr, $jiten) ? "https://kanji.jitenon.jp/kanji{$jiten[$charStr]}" : null ]); } }