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

有没有一种可靠的方法可以在不使用“doi:”前缀的情况下识别文本块中的 DOI?(任何可接受的语言,首选正则表达式,并且必须避免误报)

有帮助吗?

解决方案

好的,我目前正在从自由格式文本 (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] 当然)在他们的 后缀: .-()/:- ——所以,虽然 DOI 不存在 10.1016.12.31/nature.S0735-1097(98)2000/12/31/34:7-7 是完全合理的。

合理的选择是使用 \S 或者 [[:graph:]] PCRE 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';

, 这是一个演示.

其他提示

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

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

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

CrossRef 有推荐, ,他们在 99.3% 的 DOI 上测试成功:

/^10.\d{4,9}/[-._;()/:A-Z0-9]+$/i

我确信目前这对OP来说并不是超级有帮助,但我想我应该发布我正在尝试的内容,以防像我这样的其他人偶然发现这一点:

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

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

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

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

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

这是我的做法:

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

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

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

  • <geo coords="10.4515260,51.1656910"></geo>

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

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

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

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

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

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

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

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

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

候选人 doi 在哪里,

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top