参考文献的作者数变成6
This commit is contained in:
@@ -47,6 +47,15 @@ class BookCitationParser
|
||||
$out['isbn'] = $this->matchIsbn($clean);
|
||||
$clean = $this->stripTail($clean);
|
||||
|
||||
// APA 格式:"作者 (年份). 书名 (第N版). 出版社." —— 年份括号是很硬的锚点,优先按它切
|
||||
if ($this->takeApa($clean, $out)) {
|
||||
if ($this->needsLlm($out)) {
|
||||
$out = $this->refineByLlm($clean, $out);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
// 章节引用:"章节作者. 章节名. In: 编者. 书名. 版次. 地点: 出版社; 年. 页码"
|
||||
// 出版信息属于 In: 之后的那本书,必须分开解析,否则会把编者当成书名
|
||||
if (preg_match('/^(.*?)\bIn\s*:\s*(.+)$/isu', $clean, $m) && trim($m[1]) !== '' && trim($m[2]) !== '') {
|
||||
@@ -126,6 +135,146 @@ class BookCitationParser
|
||||
return preg_replace('/[^0-9Xx]/', '', $m[1]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// APA 格式
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* "Duffy, E., Hockenberry, M., & Gibbs, K. (2023). Wong's Nursing Care of
|
||||
* Infants and Children (12th ed.). Elsevier."
|
||||
*/
|
||||
private function takeApa($text, array &$out)
|
||||
{
|
||||
if (!preg_match('/^(.{2,300}?)\s*\(\s*(\d{4})[a-z]?\s*\)\s*\.\s*(.+)$/su', $text, $m)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$author = preg_replace('/\(\s*(?:Ed|Eds|Editor|Editors)\.?\s*\)/iu', '', $m[1]);
|
||||
$out['author'] = $this->normalizeApaAuthors(trim($author, " .,&"));
|
||||
$out['year'] = $m[2];
|
||||
|
||||
// 章节引用:"章节名. In A. Editor (Ed.), 书名 (pp. 1-10). 出版社."
|
||||
// 必须先认出 (Ed.) 再摘括注,否则 (Ed.) 会被当成版次括注先摘掉
|
||||
$rest = trim($m[3]);
|
||||
$containerPart = '';
|
||||
if (preg_match('/^(.+?)[\.,]\s*\bIn\b\s+.+?\(\s*Eds?\.?\s*\)\s*,\s*(.+)$/isu', $rest, $cm)) {
|
||||
$rest = trim($cm[1]);
|
||||
$containerPart = trim($cm[2]);
|
||||
}
|
||||
|
||||
$rest = $this->takeApaParentheticals($rest, $out);
|
||||
if ($containerPart !== '') {
|
||||
$containerPart = $this->takeApaParentheticals($containerPart, $out);
|
||||
}
|
||||
|
||||
$segments = $this->apaSegments($containerPart !== '' ? $containerPart : $rest);
|
||||
if (empty($segments)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// APA 的出版社在最后一段,其余都算书名
|
||||
if (count($segments) >= 2) {
|
||||
$out['publisher'] = array_pop($segments);
|
||||
}
|
||||
$mainTitle = $this->cleanTitle(implode('. ', $segments));
|
||||
|
||||
if ($containerPart !== '') {
|
||||
$out['container'] = $mainTitle;
|
||||
$chapter = $this->apaSegments($rest);
|
||||
$out['title'] = $this->cleanTitle(implode('. ', $chapter));
|
||||
} else {
|
||||
$out['title'] = $mainTitle;
|
||||
}
|
||||
|
||||
return $out['title'] !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 摘掉 APA 的括注版次与页码:"(12th ed.)"、"(pp. 1-10)"、"(2nd ed., pp. 1-10)",
|
||||
* 书名自带的括注(如 "(NIC)")不含 ed./pp.,会原样留下
|
||||
*/
|
||||
private function takeApaParentheticals($text, array &$out)
|
||||
{
|
||||
if (!preg_match_all('/\(([^)]*(?:\bedn?\.|\bedition\b|\bpp?\.)[^)]*)\)/iu', $text, $ms, PREG_SET_ORDER)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
foreach ($ms as $item) {
|
||||
$inner = $item[1];
|
||||
$edition = $this->matchEdition($inner);
|
||||
if ($edition !== '' && $out['edition'] === '') {
|
||||
$out['edition'] = $edition;
|
||||
}
|
||||
if ($out['pages'] === ''
|
||||
&& preg_match('/\bpp?\.\s*([\dA-Za-z]+(?:\s*[-\x{2013}]\s*[\dA-Za-z]+)?)/iu', $inner, $pm)) {
|
||||
$out['pages'] = preg_replace('/\s+/', '', $pm[1]);
|
||||
}
|
||||
$text = str_replace($item[0], ' ', $text);
|
||||
}
|
||||
|
||||
return trim(preg_replace('/\s+/u', ' ', $text));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function apaSegments($text)
|
||||
{
|
||||
$segments = [];
|
||||
foreach ($this->splitSegments($text) as $seg) {
|
||||
$seg = trim($seg, " .,;");
|
||||
if ($seg !== '') {
|
||||
$segments[] = $seg;
|
||||
}
|
||||
}
|
||||
|
||||
return $segments;
|
||||
}
|
||||
|
||||
/**
|
||||
* APA 姓名表 → 温哥华式,与期刊那条链路和 References 的渲染方式保持一致
|
||||
* "Duffy, E., Hockenberry, M., & Gibbs, K." → "Duffy E, Hockenberry M, Gibbs K"
|
||||
*/
|
||||
private function normalizeApaAuthors($author)
|
||||
{
|
||||
$author = trim((string)$author);
|
||||
$author = preg_replace('/\s*&\s*/u', ', ', $author);
|
||||
$author = preg_replace('/(\s*,\s*)+/u', ', ', $author);
|
||||
if ($author === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// 没有"姓, 名缩写"结构的(机构作者等)原样保留
|
||||
if (!preg_match('/,\s*\p{Lu}[\p{L}]*\./u', $author)) {
|
||||
return $author;
|
||||
}
|
||||
|
||||
$tokens = preg_split('/\s*,\s*/u', $author);
|
||||
if (!is_array($tokens) || count($tokens) < 2 || count($tokens) % 2 !== 0) {
|
||||
return $author;
|
||||
}
|
||||
|
||||
$names = [];
|
||||
for ($i = 0; $i < count($tokens); $i += 2) {
|
||||
$surname = trim($tokens[$i], " .");
|
||||
$given = trim($tokens[$i + 1], " .");
|
||||
if (!preg_match('/^\p{Lu}[\p{L}\'\-\s]*$/u', $surname)
|
||||
|| !preg_match('/^\p{Lu}[\p{L}\.\s]*$/u', $given)) {
|
||||
return $author;
|
||||
}
|
||||
|
||||
$initials = '';
|
||||
foreach (preg_split('/[\s\.]+/u', $given) as $word) {
|
||||
if ($word !== '') {
|
||||
$initials .= mb_strtoupper(mb_substr($word, 0, 1), 'UTF-8');
|
||||
}
|
||||
}
|
||||
$names[] = $initials === '' ? $surname : $surname . ' ' . $initials;
|
||||
}
|
||||
|
||||
return implode(', ', $names);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 作者
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user