/** * @param string[][][] $fieldsAsMultiDimensionalArrays * @param string[] $metadata * @param string[] $files * @return Dictionary */ protected function generateDictionary(array $fieldsAsMultiDimensionalArrays, array $metadata, array $files) : Dictionary { if ($files) { $tempDirectory = (new \esperecyan\dictionary_php\parser\GenericDictionaryParser())->generateTempDirectory(); foreach ($files as $filename => $file) { file_put_contents("{$tempDirectory}/{$filename}", $file); } } $dictionary = new Dictionary(isset($tempDirectory) ? new \FilesystemIterator($tempDirectory) : null); foreach ($fieldsAsMultiDimensionalArrays as $fieldsAsMultiDimensionalArray) { $dictionary->addWord($fieldsAsMultiDimensionalArray); } $dictionary->setMetadata($metadata); return $dictionary; }
/** * @param \SplFileInfo $file * @param string|null $filename * @param string|null $title * @throws SyntaxException お題の数、辞書全体の文字数が制限範囲外であるとき。 * @return Dictionary */ public function parse(\SplFileInfo $file, string $filename = null, string $title = null) : Dictionary { $dictionary = new Dictionary(); $words = []; if (!$file instanceof \SplFileObject) { $file = $file->openFile(); } else { $file->rewind(); } $file->setFlags(\SplFileObject::DROP_NEW_LINE | \SplFileObject::READ_AHEAD | \SplFileObject::SKIP_EMPTY); foreach ($file as $line) { $word = $this->parseLine($line); if (!in_array($word, $words)) { $dictionary->addWord(['text' => [str_replace('ヴ', 'ゔ', $line)]]); $words[] = $word; } } $wordsLength = count($words); if ($wordsLength < self::WORDS_MIN) { throw new SyntaxException(sprintf(_('お題が%1$d個しかありません。%2$d個以上必要です。'), $wordsLength, self::WORDS_MIN)); } if ($wordsLength > self::WORDS_MAX) { throw new SyntaxException(sprintf(_('お題が%1$d個あります。%2$d個以内にする必要があります。'), $wordsLength, self::WORDS_MAX)); } $dictionaryCodePoints = mb_strlen(implode('', $words), 'UTF-8'); if ($dictionaryCodePoints > self::DICTIONARY_CODE_POINTS_MAX) { throw new SyntaxException(sprintf(_('辞書全体で%1$d文字あります。%2$d文字以内にする必要があります。'), $dictionaryCodePoints, self::DICTIONARY_CODE_POINTS_MAX)); } if (!is_null($title) || !is_null($filename)) { if (!is_null($title) && $title !== '') { $trimedTitle = preg_replace('/^[ \\t]+|[ \\t]+$/u', '', $title); } if (!is_null($filename) && (!isset($trimedTitle) || $trimedTitle === '')) { $trimedTitle = preg_replace('/^[ \\t]+|[ \\t]+$/u', '', (new GenericDictionaryParser())->getTitleFromFilename($filename)); } if (isset($trimedTitle) && $trimedTitle !== '') { $dictionary->setMetadata(['@title' => $trimedTitle]); $titleLength = $this->getLengthAs16BitCodeUnits($trimedTitle); if ($titleLength > self::TITLE_MAX) { $this->logger->error(sprintf(_('辞書名が%1$d文字 (補助文字は2文字扱い) あります。ピクトセンスにおける辞書名の最大文字数は%2$d文字です。'), $titleLength, self::TITLE_MAX)); } } else { $this->logger->error(_('辞書名が空です。先頭末尾の空白は取り除かれます。')); } } return $dictionary; }
/** * CSVの一レコードを表す2つの配列によってお題を追加します。 * @param Dictionary $dictionary * @param string[] $fieldNames * @param string[] $fields * @param bool $first ヘッダ行を除く最初のレコードであれば真。 * @throws SyntaxException */ protected function addRecord(Dictionary $dictionary, array $fieldNames, array $fields, bool $first) { if (!in_array('text', $fieldNames)) { throw new SyntaxException(sprintf(_('ヘッダ行「%s」にフィールド名「text」が存在しません'), $this->convertToCSVRecord($fieldNames))); } if (count($fields) > count($fieldNames)) { throw new SyntaxException(sprintf(_('「%s」のフィールド数は、ヘッダ行のフィールド名の数を超えています。'), $this->convertToCSVRecord($fields))); } foreach ($fields as $i => $field) { if ($field !== '') { if ($fieldNames[$i][0] === '@') { if ($first) { $metaFields[$fieldNames[$i]] = $field; } else { $this->logger->error(sprintf(_('メタフィールド%sの内容は、最初のレコードにのみ記述可能です。'), $fieldNames[$i])); } } else { $fieldsAsMultiDimensionalArray[$fieldNames[$i]][] = $field; } } } if (!isset($fieldsAsMultiDimensionalArray['text'][0])) { throw new SyntaxException(sprintf(_('「%s」にはtextフィールドが存在しません。'), $this->convertToCSVRecord($fields))); } $dictionary->addWord($fieldsAsMultiDimensionalArray); if (isset($metaFields)) { $dictionary->setMetadata($metaFields); } }