在文档或页面中查找DOI
DOI系统基本上不构成对合理标识符构成有用的限制。 但是,将DOI引出PDF,网页等对于引用信息等是非常有用的。
有没有可靠的方法来识别一个文本块中的一个DOI,而不用假设'doi:'前缀? (任何可接受的语言,正则expression式都是首选,避免误报是必须的)
好吧,我目前从自由格式文本(XML)中提取数以千计的DOI,并且我意识到我以前的方法有一些问题,即关于编码实体和尾随标点符号,所以我继续阅读规范 ,这是最好的可以来。
DOI前缀应由一个目录指示符和一个注册人代码组成。 这两个组成部分应以句号(句点)分隔。
目录指示符应为“10”。 目录指示符将整组string(前缀和后缀)区分为分辨率系统内的数字对象标识符。
很简单,最初的\b
防止我们“匹配”一个不以10.
开头的“DOI” 10.
$pattern = '\b(10[.]';
DOI前缀的第二个元素应该是注册人代码。 注册人代码是分配给注册人的唯一string。
此外,所有分配的注册人代码都是数字的,并且至less有4位数字,因此:
$pattern = '\b(10[.][0-9]{4,}';
如果需要的话,注册人代码可以进一步分成子元素以便pipe理。 注册人代码的每个子元素之前都应有一个句号。
$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*';
DOI语法应由正斜杠分隔的DOI前缀和DOI后缀组成。
然而,这不是绝对必要的,第2.2.3节指出不常见的后缀系统可能会使用其他约定(如10.1000.123456
而不是10.1000/123456
),但是可以减less一些松弛。
$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/';
DOI号不区分大小写,可以包含Unicode的合法graphics字符中的任何可打印字符。 DOI后缀应由注册人select的任意长度的string组成。 每个后缀对于前面的前缀元素都是唯一的。 唯一的后缀可以是序列号,也可以包含从另一个系统生成或基于另一个系统生成的标识符。
现在,这是从我处理的所有DOI中变得更加棘手的地方,我看到以下字符(当然除了[0-9a-zA-Z]
) 后缀 : .-()/:-
-虽然它不存在,DOI 10.1016.12.31/nature.S0735-1097(98)2000/12/31/34:7-7
是完全合理的。
合乎逻辑的select是使用\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:]]
类的超集,它包含了在自由文本或任何标记语言中容易find的字符: "'&<>
等等。
现在让我们使用一个负面的lookahead来过滤标记:
$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])\S)+'; // or $pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])[[:graph:]])+';
上面应该包括编码的实体( &
),属性引号( ["']
)和打开/closures标签( [<>]
)。
与标记语言不同,自由文本通常不会使用标点符号,除非它们至less有一个空格或放在句尾,例如:
这是一个很长的DOI:
10.1016.12.31/nature.S0735-1097(98)2000/12/31/34:7-7
:10.1016.12.31/nature.S0735-1097(98)2000/12/31/34:7-7
!!!
这里的解决scheme是closures我们的捕获组,并断言另一个字的边界:
$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])\S)+)\b'; // or $pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])[[:graph:]])+)\b';
瞧 , 这是一个演示 。
@西拉斯理智的检查是一个好主意。 然而,正则expression式并不涵盖所有的DOI。 第一个元素(当前)必须是10,而第二个元素(现在)必须是数字,但是第三个元素几乎不受限制:
“合法字符是Unicode的合法graphics字符,具体排除了控制字符范围0x00-0x1F和0x80-0x9F …”
这就是真正的问题所在。 在实践中,我从来没有见过空白,但规范特别允许它。 基本上,似乎没有一个明智的方式来检测DOI的结束 。
我相信这对OP来说并不是很有帮助,但是我想我会发布我正在尝试的,以防像我这样的其他人绊倒在这里:
(10.(\d)+/(\S)+)
这匹配:“10点数字斜杠什么,不是空白”
但是对于我的使用(刮HTML),这是发现误报,所以我必须匹配以上,加上摆脱引号和大于/小于:
(10.(\d)+/([^(\s\>\"\<)])+)
我仍然在testing这些,但是我现在感到很有希望。
这是我去的地方:
(10[.][0-9]{4,}[^\s"/<>]*/[^\s"<>]+)
还有一些有效的边缘情况下,这不会失败,但其他人似乎这样做:
-
10.1007/978-3-642-28108-2_19
-
10.1007.10/978-3-642-28108-2_19
(虚构例子,请参阅@ Ju9OR评论 ) -
10.1016/S0735-1097(98)00347-7
-
10.1579/0044-7447(2006)35\[89:RDUICP\]2.0.CO;2
此外,正确地丢弃一些虚假(X | HT)ML的东西,如:
-
<geo coords="10.4515260,51.1656910"></geo>
这是一个非常古老和回答的问题,但这是另一个潜在的替代品。
\b10\.(\d+\.*)+[\/](([^\s\.])+\.*)+\b
这假定白色空间不是DOI的一部分。
还没有testing过这个误报,但它似乎能够find本页提到的所有边缘案例。
下面的正则expression式应该做这个工作(Perl正则expression式语法):
/(10\.\d+\/\d+)/
你可以通过打开url做一些额外的理智检查
http://hdl.handle.net/<doi>
和
http://dx.doi.org/<doi>
候选人在哪里,
并testing你a)得到一个200 OK的http状态,b)返回的页面不是服务的“DOI not found”页面。