bib文件生成

This commit is contained in:
wangjinlei
2025-12-17 15:54:45 +08:00
parent 73bbc843a9
commit 987197ea3c

View File

@@ -2015,6 +2015,397 @@ class Production extends Base
} }
public function mytestbib(){
$data = $this->request->post();
$rule = new Validate([
"article_id"=>"require"
]);
if(!$rule->check($data)){
return jsonError($rule->getError());
}
$file = $this->generateBibFile($data['article_id']);
return jsonSuccess(['file'=>$file]);
}
/**
* 生成指定文章的 BibTeX 文件
* @param int $p_article_id 生产文章ID
* @param string $outputPath 输出文件路径(可选)
* @return string 生成的文件路径
*/
public function generateBibFile($article_id, $outputPath = null)
{
$production_article_obj = $this->production_article_obj->where("article_id",$article_id)->find();
if($production_article_obj==null){
$this->addProductionEx($article_id);
$production_article_obj = $this->production_article_obj->where("article_id",$article_id)->find();
}
if (!$outputPath) {
$outputPath = ROOT_PATH . 'public' . DS . 'latex' . DS . 'tex_'.$article_id . DS .'references_' . $article_id . '.bib';
}
$dir = dirname($outputPath);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
$bibContent = $this->generateBibContent($production_article_obj['p_article_id']);
file_put_contents($outputPath, $bibContent);
return $outputPath;
}
/**
* 获取参考文献数据
* @param int $p_article_id 生产文章ID
* @return array 参考文献数组
*/
private function getReferences($p_article_id)
{
return $this->production_article_refer_obj->where("p_article_id",$p_article_id)->where("state",0)->select();
// $sql = "SELECT * FROM t_production_article_refer
// WHERE p_article_id = :p_article_id
// AND state = 0
// ORDER BY `index`";
//
// $stmt = $this->db->prepare($sql);
// $stmt->bindParam(':p_article_id', $p_article_id, PDO::PARAM_INT);
// $stmt->execute();
//
// return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 生成 BibTeX 内容
* @param array $references 参考文献数据
* @param int $p_article_id 文章ID
* @return string BibTeX 内容
*/
private function generateBibContent( $p_article_id)
{
$content = "% BibTeX file generated for article ID: {$p_article_id}\n";
$content .= "% Generated on " . date('Y-m-d H:i:s') . "\n\n";
$references = $this->production_article_refer_obj->where("p_article_id",$p_article_id)->where("state",0)->select();
foreach ($references as $ref) {
$entry = $this->generateBibEntry($ref);
if ($entry) {
$content .= $entry . "\n\n";
}
}
return $content;
}
/**
* 生成单个 BibTeX 条目
* @param array $ref 参考文献数据
* @return string|null BibTeX 条目或 null
*/
private function generateBibEntry($ref)
{
// 使用 DOI 或索引作为 citation key
$citationKey = $this->generateCitationKey($ref);
// 如果有解析后的作者和标题信息,优先使用
if (!empty($ref['author']) && !empty($ref['title'])) {
return $this->generateFromParsedData($ref, $citationKey);
}
// 否则尝试从原始内容解析
else {
return ;
// return $this->generateFromRawContent($ref, $citationKey);
}
}
/**
* 生成 citation key
* @param array $ref 参考文献数据
* @return string citation key
*/
private function generateCitationKey($ref)
{
if (!empty($ref['refer_doi'])) {
// 使用 DOI 的部分作为 key
$parts = explode('/', $ref['refer_doi']);
if (count($parts) > 1) {
return str_replace('.', '_', end($parts));
}
}
// 默认使用索引
return 'ref_' . $ref['p_refer_id'];
}
private function parsePublicationInfo($referenceText)
{
$result = [
'year' => '',
'volume' => '',
'number' => '',
'pages' => ''
];
// 匹配模式year;volume(number):pages
$pattern = '/(\d{4})\s*;\s*(\d+)(?:\(([^)]+)\))?(?:\s*:\s*([a-zA-Z0-9\u2013\u2014\-]+(?:\s*[\u2013\u2014\-]\s*[a-zA-Z0-9]+)?))?/';
if (preg_match($pattern, $referenceText, $matches)) {
$result['year'] = isset($matches[1]) ? $matches[1] : '';
$result['volume'] = isset($matches[2]) ? $matches[2] : '';
// 期号可能是可选的
if (isset($matches[3]) && $matches[3] !== '') {
$result['number'] = $matches[3];
}
// 页码也是可选的
if (isset($matches[4]) && $matches[4] !== '') {
$result['pages'] = $matches[4];
}
} else {
// 如果标准模式不匹配,尝试更宽松的匹配方式
$result = self::parseLooseFormat($referenceText);
}
return $result;
}
private function parseLooseFormat($referenceText)
{
$result = [
'year' => '',
'volume' => '',
'number' => '',
'pages' => ''
];
// 提取年份4位数字
if (preg_match('/\b(\d{4})\b/', $referenceText, $yearMatches)) {
$result['year'] = $yearMatches[1];
}
// 提取卷号和期号(格式如 54(4) 或 54 (4)
if (preg_match('/(\d+)\s*\(?(\d*)\)?\s*:?\s*([a-zA-Z0-9\-]*)/', $referenceText, $volMatches)) {
if (isset($volMatches[1])) {
$result['volume'] = $volMatches[1];
}
if (isset($volMatches[2]) && $volMatches[2] !== '') {
$result['number'] = $volMatches[2];
}
if (isset($volMatches[3]) && $volMatches[3] !== '') {
$result['pages'] = $volMatches[3];
}
}
return $result;
}
/**
* 从解析后的数据生成 BibTeX 条目
* @param array $ref 参考文献数据
* @param string $citationKey citation key
* @return string BibTeX 条目
*/
private function generateFromParsedData($ref, $citationKey)
{
$entry = "@article{{$citationKey},\n";
// 添加已解析的字段
if (!empty($ref['author'])) {
$entry .= " author={" . $this->escapeBibTeX($this->formatBibTeXAuthors($ref['author'])) . "},\n";
}
if (!empty($ref['title'])) {
$entry .= " title={" . $this->escapeBibTeX($ref['title']) . "},\n";
}
if (!empty($ref['joura'])) {
$entry .= " journal={" . $this->escapeBibTeX($ref['joura']) . "},\n";
}
// 解析并添加出版信息
if (!empty($ref['dateno'])) {
$pubInfo = $this->parsePublicationInfo($ref['dateno']);
if (!empty($pubInfo['year'])) {
$entry .= " year={" . $this->escapeBibTeX($pubInfo['year']) . "},\n";
}
if (!empty($pubInfo['volume'])) {
$entry .= " volume={" . $this->escapeBibTeX($pubInfo['volume']) . "},\n";
}
if (!empty($pubInfo['number'])) {
$entry .= " number={" . $this->escapeBibTeX($pubInfo['number']) . "},\n";
}
if (!empty($pubInfo['pages'])) {
$entry .= " pages={" . $this->escapeBibTeX($pubInfo['pages']) . "},\n";
}
}
if (!empty($ref['refer_doi'])) {
$entry .= " doi={" . $this->escapeBibTeX($ref['refer_doi']) . "},\n";
}
// 移除最后一个逗号并关闭条目
$entry = rtrim($entry, ",\n") . "\n}";
return $entry;
}
/**
* 格式化作者信息为BibTeX格式
* @param string $authors 作者字符串,如 "Li Y, Yang C, Zhao H, Qu S, Li X, Li Y"
* @return string 格式化后的作者字符串,如 "Li, Y. and Yang, C. and Zhao, H. and Qu, S. and Li, X. and Li, Y."
*/
private function formatBibTeXAuthors($authors) {
$authors = rtrim($authors, ". \t\n\r\0\x0B");
// 如果包含"et al",则原样保留
if (stripos($authors, 'et al') !== false) {
return $authors;
}
// 按逗号分割各个作者
$authorArray = array_map('trim', explode(',', $authors));
$formattedAuthors = [];
foreach ($authorArray as $author) {
$author = trim($author);
if (empty($author)) {
continue;
}
// 按空格分割作者的各部分
$authorParts = explode(' ', $author);
if (count($authorParts) >= 2) {
// 最后一个是姓氏,前面的是名字首字母
$lastName = array_pop($authorParts);
$firstName = implode(' ', $authorParts);
$formattedAuthors[] = $firstName.", ".$lastName;
// $firstNameInitials = implode('. ', $authorParts) . '.';
// $formattedAuthors[] = $lastName . ', ' . $firstNameInitials;
} else {
// 如果只有一个部分,当作姓氏处理
$formattedAuthors[] = $author;
}
}
// 用 " and " 连接所有作者
return implode(' and ', $formattedAuthors);
}
/**
* 从原始内容生成 BibTeX 条目(简单处理)
* @param array $ref 参考文献数据
* @param string $citationKey citation key
* @return string BibTeX 条目
*/
private function generateFromRawContent($ref, $citationKey)
{
$entry = "@misc{{$citationKey},\n";
// 将整个参考文献内容作为 note 字段
if (!empty($ref['refer_content'])) {
$entry .= " note={" . $this->escapeBibTeX($ref['refer_content']) . "},\n";
}
if (!empty($ref['refer_doi'])) {
$entry .= " doi={" . $this->escapeBibTeX($ref['refer_doi']) . "},\n";
}
// 移除最后一个逗号并关闭条目
$entry = rtrim($entry, ",\n") . "\n}";
return $entry;
}
/**
* 转义 BibTeX 特殊字符
* @param string $text 文本内容
* @return string 转义后的内容
*/
private function escapeBibTeX($text)
{
// 转义大括号
$text = str_replace(['{', '}'], ['\\{', '\\}'], $text);
// 转义反斜杠
$text = str_replace('\\', '\\\\', $text);
return $text;
}
// 在 Production 控制器中添加以下方法:
// 在 Production.php 中添加以下方法:
/**
* 生成 BibTeX 文件
*/
public function generateBibtex()
{
$data = $this->request->post();
$rule = new Validate([
'p_article_id' => 'require|number'
]);
if (!$rule->check($data)) {
return jsonError($rule->getError());
}
try {
// 创建数据库连接
$db = Db::connect();
$generator = new ReferenceBibGenerator($db);
// 生成 BibTeX 文件
$filePath = $generator->generateBibFile($data['p_article_id']);
// 返回相对路径供前端使用
$relativePath = str_replace(ROOT_PATH . 'public' . DS, '', $filePath);
return jsonSuccess([
'file_path' => $relativePath,
'full_path' => $filePath
]);
} catch (Exception $e) {
return jsonError('生成 BibTeX 文件失败: ' . $e->getMessage());
}
}
/**
* 下载 BibTeX 文件
*/
public function downloadBibtex()
{
$p_article_id = $this->request->param('p_article_id', 0);
if (!$p_article_id) {
return jsonError('缺少参数');
}
$filePath = ROOT_PATH . 'public' . DS . 'bibtex' . DS . 'references_' . $p_article_id . '.bib';
if (!file_exists($filePath)) {
return jsonError('文件不存在');
}
// 设置下载头信息
header('Content-Type: application/x-bibtex');
header('Content-Disposition: attachment; filename="references_' . $p_article_id . '.bib"');
header('Content-Length: ' . filesize($filePath));
// 输出文件内容
readfile($filePath);
exit;
}
public function getFragBF() public function getFragBF()
{ {
$data = $this->request->post(); $data = $this->request->post();