DOIシステムは、合理的な識別子を構成するものに対して基本的に有用な制限を設けていません。ただし、PDF や Web ページなどから DOI を取得できることは、引用情報などに非常に役立ちます。
「doi:」プレフィックスを想定せずに、テキスト ブロック内の DOI を識別する信頼できる方法はありますか? (任意の言語を受け入れ、正規表現を優先し、誤検知を回避する必要があります)
OK、私は現在、自由形式のテキスト (XML) から何千もの DOI を抽出していますが、以前のアプローチには、エンコードされたエンティティと末尾の句読点に関していくつかの問題があることに気付きました。一緒に来ることができました。
DOI プレフィックスは、登録者コードが続くディレクトリ インジケータで構成されます。これらの 2 つのコンポーネントは、ピリオド (ピリオド) で区切る必要があります。
ディレクトリインジケータは「10」とする。ディレクトリ インジケータは、文字列のセット全体 (プレフィックスとサフィックス) を解決システム内のデジタル オブジェクト識別子として識別します。
簡単に言えば、イニシャル\b
は、で始まらない「DOI」に「一致」することを防ぎ10.
ます。
$pattern = '\b(10[.]';
DOI プレフィックスの 2 番目の要素は登録者コードです。登録者コードは、登録者に割り当てられる一意の文字列です。
また、割り当てられたすべての登録者コードは数字であり、少なくとも 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]
ました。.-()/:-
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:]])+';
上記は、エンコードされたエンティティ ( &
)、属性の引用符 ( ["']
)、開始/終了タグ ( [<>]
) をカバーする必要があります。
マークアップ言語とは異なり、フリー テキストでは通常、句読点が少なくとも 1 つのスペースで区切られているか、文末に配置されていない限り、句読点を使用しません。たとえば、次のようになります。
これは長い 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 でなければならず、2 番目の要素は (現在) 数値でなければなりませんが、3 番目の要素はほとんど制限されていません。
「有効な文字は、Unicode の有効なグラフィック文字です。これは、制御文字範囲 0x00-0x1F および 0x80-0x9F を明確に除外します...」
そして、そこに本当の問題があります。実際には、空白が使用されているのを見たことがありませんが、仕様では明確に許可されています。基本的に、DOIの終わりを検出する賢明な方法はないようです。
現時点では、OPにとってあまり役に立たないと思いますが、私のような他の誰かがこれに遭遇した場合に備えて、私が試していることを投稿すると思いました。
(10.(\d)+/(\S)+)
これは次のように一致します:「10ドットの数字は空白ではなく何でもスラッシュ」
しかし、私の使用(HTMLのスクレイピング)では、これは誤検知を検出していたため、上記に一致する必要があり、さらに引用符と大なり/小なりを削除する必要がありました。
(10.(\d)+/([^(\s\>\"\<)])+)
私はまだこれらをテストしていますが、これまでのところ希望を感じています。
これが私のやり方です:
(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の一部ではないことを前提としています。
誤検知についてこれをテストしていませんが、このページに記載されているすべてのエッジ ケースを見つけることができるようです。
次の正規表現は、その仕事を行う必要があります (Perl 正規表現構文):
/(10\.\d+\/\d+)/
URLを開くことで、追加の健全性チェックを行うことができます
http://hdl.handle.net/<doi>
と
http://dx.doi.org/<doi>
ドイ候補はどこだ
a) 200 OK http ステータスを取得すること、および b) 返されたページがサービスの「DOI が見つかりません」ページではないことをテストします。