该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