PAYATHON 2026

openxlsx2 添加长超链接时出现 Error: stoi

排障赵师傅

结论

问题不在超链接长度。两个地址长度相同,表现却不同,说明 Error: stoi 是 openxlsx2 解析超链接目标内容时产生的,与 Excel 的 255 字符限制无关。

查询表达式中含有 (、)、: 和 + 等 URL 保留字符。未经编码就传给 wb_add_hyperlink(),可能会触发 openxlsx2 某些版本的解析缺陷,导致底层 C++ 代码抛出含义不明确的 stoi 异常。accession 不同,待解析的完整字符串也会变化,因此两个链接即使长度相同,也可能只有一个报错。

可以按以下方式处理:

  1. 只对查询参数进行 URL 编码;
  2. 将链接明确写成外部链接;
  3. 不要对完整 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() 输出。

备注:内容仅供参考。