Ali*_*xel 52
好吧,我目前正在从自由格式文本(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';
而且瞧,这里是一个演示.
Kai*_*Kai 12
@Silas理智检查是一个好主意.但是,正则表达式并不涵盖所有DOI.第一个元素必须(当前)为10,第二个元素必须(当前)为数字,但第三个元素几乎不受限制:
"合法字符是Unicode的合法图形字符.这特别排除了控制字符范围0x00-0x1F和0x80-0x9F ......"
这就是真正的问题所在.在实践中,我从未见过使用的空格,但规范明确允许使用它.基本上,似乎没有一种合理的方法来检测DOI 的结束.
CrossRef的建议是,他们已在99.3%的DOI上成功进行了测试:
/^10.\d{4,9}/[-._;()/:A-Z0-9]+$/i