55

DOI系统对合理标识符的构成基本上没有任何有用的限制。但是,能够从 PDF、网页等中提取 DOI 对于引文信息等非常有用。

有没有一种可靠的方法来识别文本块中的 DOI 而无需假设“doi:”前缀?(任何可接受的语言,首选正则表达式,并且必须避免误报)

4

7 回答 7

61

好的,我目前正在从自由格式文本 (XML) 中提取数千个 DOI,我意识到我以前的方法存在一些问题,即关于编码实体和尾随标点符号,所以我继续阅读规范,这是我最好的可以来。


DOI 前缀应由一个目录指示符和一个注册者代码组成。这两个组件应由句号(句号)分隔。

目录指示符应为“10”。目录指示符将整个字符串集(前缀和后缀)区分为解析系统中的数字对象标识符。

很简单,首字母会\b阻止我们“匹配”不以 开头的“DOI” 10.

$pattern = '\b(10[.]';

DOI 前缀的第二个元素是注册人代码。注册人代码是分配给注册人的唯一字符串。

此外,所有分配的注册人代码都是数字,并且长度至少为 4 位,因此:

$pattern = '\b(10[.][0-9]{4,}';

如果需要,为了管理方便,注册人代码可以进一步划分为子元素。注册人代码的每个子元素之前都应有句号。

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*';


DOI 语法应由 DOI 前缀和 DOI 后缀组成,由正斜杠分隔。

但是,这不是绝对必要的,第 2.2.3 节指出不常见的后缀系统可以使用其他约定(例如10.1000.123456代替10.1000/123456),但让我们稍微松懈一下。

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/';


DOI 号不区分大小写,可以包含 Unicode 合法图形字符中的任何可打印字符。DOI 后缀应由注册人选择的任意长度的字符串组成。每个后缀对于它之前的前缀元素应该是唯一的。唯一的后缀可以是一个序列号,或者它可能包含从另一个系统生成或基于另一个系统的标识符。

现在这是变得更棘手的地方,从我处理的所有 DOI 中,我[0-9a-zA-Z]在它们的后缀中看到了以下字符(当然,除了) :.-()/:--- 所以,虽然它不存在,但 DOI10.1016.12.31/nature.S0735-1097(98)2000/12/31/34:7-7是完全合理的。

合乎逻辑的选择是使用\SPCRE [[:graph:]]POSIX 类,所以让我们这样做:

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/\S+'; // or

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/[[:graph:]]+';


现在我们有一个难题,[[:graph:]]该类是该类的超集[[:punct:]],其中包括在自由文本或任何标记语言中容易找到的字符:"'&<>等等。

现在让我们使用负前瞻过滤标记:

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])\S)+'; // or

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])[[:graph:]])+';


以上内容应涵盖编码实体 ( &)、属性引号 ( ["']) 和打开/关闭标签 ( [<>])。

与标记语言不同,自由文本通常不使用标点符号,除非它们以至少一个空格为界放置在句子的末尾,例如:

这是一个很长的 DOI: 10.1016.12.31/nature.S0735-1097(98)2000/12/31/34:7-7!!!

这里的解决方案是关闭我们的捕获组并声明另一个单词边界:

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])\S)+)\b'; // or

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])[[:graph:]])+)\b';

,这是一个演示

于 2012-04-25T22:35:52.637 回答
19

CrossRef 有一个建议,他们成功地测试了 99.3% 的 DOI(他们知道):

/^10.\d{4,9}/[-._;()/:A-Z0-9]+$/i
于 2018-01-30T14:41:43.907 回答
14

@Silas 健全性检查是个好主意。但是,正则表达式并未涵盖所有 DOI。第一个元素(当前)必须是 10,第二个元素(当前)必须是数字,但第三个元素几乎没有限制:

“合法字符是Unicode的合法图形字符。这里专门排除控制字符范围0x00-0x1F和0x80-0x9F...”

这就是真正的问题所在。在实践中,我从未见过使用空格,但规范特别允许使用它。基本上,似乎没有一种明智的方法来检测 DOI 的结束

于 2008-08-27T09:04:36.743 回答
4

我确信此时它对 OP 没有太大帮助,但我想我会发布我正在尝试的内容,以防像我这样的其他人偶然发现这一点:

(10.(\d)+/(\S)+)

这匹配:“10 点数​​字斜线任何非空白”

但是对于我的使用(抓取 HTML),这是发现误报,所以我必须匹配上面的内容,加上去掉引号和大于/小于:

(10.(\d)+/([^(\s\>\"\<)])+)

我仍在测试这些,但到目前为止我感到充满希望。

于 2009-12-09T19:58:55.460 回答
3

这是我的尝试:

(10[.][0-9]{4,}[^\s"/<>]*/[^\s"<>]+)

还有一些有效的边缘情况不会失败,但其他人似乎会这样做:

此外,正确丢弃一些虚假的 (X|HT)ML 内容,例如:

  • <geo coords="10.4515260,51.1656910"></geo>
于 2012-04-24T14:40:56.110 回答
2

这是一个非常古老且已回答的问题,但这是另一个潜在的替代品。

\b10\.(\d+\.*)+[\/](([^\s\.])+\.*)+\b

这假设空白不是 DOI 的一部分。

尚未对此进行误报测试,但它似乎能够找到此页面中提到的所有边缘情况。

于 2014-06-16T14:43:05.367 回答
1

以下正则表达式应该可以完成这项工作(Perl 正则表达式语法):

/(10\.\d+\/\d+)/

您可以通过打开网址进行一些额外的健全性检查

http://hdl.handle.net/<doi>

http://dx.doi.org/<doi>

候选人doi在哪里,

并测试您 a) 获得 200 OK http 状态,b) 返回的页面不是服务的“DOI not found”页面。

于 2008-08-27T06:51:20.747 回答