代码之家  ›  专栏  ›  技术社区  ›  Kai

在文档或页面中查找DOI

  •  61
  • Kai  · 技术社区  · 18 年前

    这个 DOI 该系统基本上对构成要素没有任何有用的限制 a reasonable identifier 然而,能够从PDF、网页等中提取DOI对于引用信息等非常有用。

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

    7 回复  |  直到 18 年前
        1
  •  49
  •   Community Mohan Dere    9 年前

    好的,我目前正在从自由格式文本(XML)中提取数千个DOI,我意识到 my previous approach 有一些问题,即关于编码实体和尾随标点符号,所以我继续阅读 the specification 这是我能带的最好的了。


    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中,我看到了以下字符(除了 [0-9a-zA-Z] 当然)在他们的 后缀 : .-()/:- --所以,虽然它不存在,但内政部 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:]]+';


    现在我们有一个难题 [[:图形:]] 类是一个超级集合 [[: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/性质。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';

    和 瞧 , here is a demo .

        2
  •  12
  •   Kai    18 年前

    CrossRef has a recommendation ,他们成功测试了99.3%的DOI(他们知道):

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

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

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

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

        4
  •  4
  •   Katrin Leinweber    8 年前

    我敢肯定,在这一点上,这对OP没有多大帮助,但我想我会发布我正在尝试的东西,以防像我这样的人偶然发现这一点:

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

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

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

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

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

        5
  •  3
  •   Community Mohan Dere    9 年前

    以下是我的做法:

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

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

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

    • <geo coords="10.4515260,51.1656910"></geo>
        6
  •  2
  •   hobwell    12 年前

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

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

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

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

    和

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

    候选doi在哪里,

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

        7
  •  0
  •   Silas Snider    18 年前

    这是一个非常古老的问题,但这里有另一个潜在的替代品。

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

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

    还没有测试过误报,但它似乎能够找到本页中提到的所有边缘情况。