openxlsx2 添加长超链接时出现 Error: stoi
结论
问题不在超链接长度。两个地址长度相同,表现却不同,说明 Error: stoi 是 openxlsx2 解析超链接目标内容时产生的,与 Excel 的 255 字符限制无关。
查询表达式中含有 (、)、: 和 + 等 URL 保留字符。未经编码就传给 wb_add_hyperlink(),可能会触发 openxlsx2 某些版本的解析缺陷,导致底层 C++ 代码抛出含义不明确的 stoi 异常。accession 不同,待解析的完整字符串也会变化,因此两个链接即使长度相同,也可能只有一个报错。
可以按以下方式处理:
- 只对查询参数进行 URL 编码;
- 将链接明确写成外部链接;
- 不要对完整 URL 使用
reserved = TRUE,否则https://也会被编码。
正确构造链接
先生成查询表达式,然后对查询参数编码:
library(openxlsx2)
pgs_small <- data.frame(
id = 245L,
plot_label = "test",
Protein.IDs = "A0A4P2L339;A0A8M6Z9J0"
)
ids <- strsplit(pgs_small$Protein.IDs, ";", fixed = TRUE)[[1]]
query <- paste(
sprintf("(accession:%s)", ids),
collapse = " OR "
)
my_links <- paste0(
"https://www.uniprot.org/uniprot/?query=",
utils::URLencode(query, reserved = TRUE)
)
my_links
生成的地址类似:
https://www.uniprot.org/uniprot/?query=%28accession%3AA0A4P2L339%29%20OR%20%28accession%3AA0A8M6Z9J0%29
再将地址写入工作簿:
wb3 <- wb_workbook()
wb3$
add_worksheet("sheet1")$
add_data_table(
x = pgs_small,
table_style = "TableStyleLight1"
)$
add_hyperlink(
dims = wb_dims(x = pgs_small, from_row = 1, cols = 2),
target = my_links,
is_external = TRUE
)
wb_save(wb3, "test3.xlsx")
如果当前 openxlsx2 版本的 add_hyperlink() 没有 is_external 参数,删除这一行即可,但仍需保留 URL 编码。
批量生成链接
实际数据中,每一行包含的 ID 数量可能不同,可以将生成过程封装成函数:
make_uniprot_link <- function(x) {
ids <- trimws(strsplit(x, ";", fixed = TRUE)[[1]])
ids <- ids[nzchar(ids)]
query <- paste(
sprintf("(accession:%s)", ids),
collapse = " OR "
)
paste0(
"https://www.uniprot.org/uniprot/?query=",
utils::URLencode(query, reserved = TRUE)
)
}
my_links <- vapply(
pgs_small$Protein.IDs,
make_uniprot_link,
character(1)
)
写入多行时,单元格范围必须与 target 的长度一致:
wb3$add_hyperlink(
dims = wb_dims(
rows = seq_len(nrow(pgs_small)) + 1L,
cols = 2
),
target = my_links,
is_external = TRUE
)
这里的 + 1L 用于跳过表头。如果要把链接写入其他行或列,需要相应调整 rows 和 cols。
注意事项
wb_add_formula() 或 HYPERLINK() 公式的限制,与工作簿关系文件中保存的普通超链接不同。使用 wb_add_hyperlink() 可以避开公式字符串的长度限制,但目标地址仍需是合法且正确编码的 URI。
不要对完整地址执行以下编码:
utils::URLencode(my_links, reserved = TRUE)
这种写法会连协议分隔符一起编码。应当先编码 query 的值,再将其与基础 URL 拼接。
如果编码 URL 后,当前环境仍能稳定复现 Error: stoi,问题更可能出在所用 openxlsx2 版本的实现上。可以先升级到可用的较新版本,再用最小示例向项目维护者报告。这个错误来自底层整数转换,单凭 Error: stoi 无法确定具体是哪个输入位置引发了异常。报告时应一并提供 packageVersion("openxlsx2")、完整目标字符串和 traceback() 输出。
备注:内容仅供参考。
