Поиск DOI в документе или на странице - PullRequest
43 голосов
/ 26 августа 2008

Система DOI практически не накладывает никаких полезных ограничений на то, что составляет разумный идентификатор . Однако возможность извлечения DOI из PDF-файлов, веб-страниц и т. Д. Весьма полезна для информации о цитировании и т. Д.

Есть ли надежный способ идентифицировать DOI в блоке текста без использования префикса 'doi:'? (любой приемлемый язык, предпочтение регулярных выражений и избегание ложных срабатываний обязательно)

Ответы [ 7 ]

51 голосов
/ 26 апреля 2012

Хорошо, в настоящее время я извлекаю тысячи DOI из текста в свободной форме (XML), и я понял, что мой предыдущий подход имел несколько проблем, а именно, касающихся закодированных сущностей и конечной пунктуации, поэтому я продолжил Чтение спецификации , и это лучшее, что я могу получить.


Префикс 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';

И вуаля , вот демка .

12 голосов
/ 27 августа 2008

@ Сайлас Проверка работоспособности - хорошая идея. Тем не менее, регулярное выражение не охватывает все DOI. Первый элемент должен (в настоящее время) быть 10, а второй элемент должен (в настоящее время) быть числовым, но третий элемент практически не ограничен:

"Допустимые символы - это допустимые графические символы Unicode. Это, в частности, исключает диапазоны управляющих символов 0x00-0x1F и 0x80-0x9F ..."

и в этом заключается настоящая проблема. На практике я никогда не видел, чтобы использовались пробелы, но спецификация специально учитывает это. По сути, не существует разумного способа определения конца DOI.

6 голосов
/ 30 января 2018

CrossRef рекомендует , чтобы они успешно прошли тестирование на 99,3% DOI:

/^10.\d{4,9}/[-._;()/:A-Z0-9]+$/i
4 голосов
/ 09 декабря 2009

Я уверен, что на данный момент это не очень полезно для ОП, но я решил опубликовать то, что я пытаюсь, на случай, если кто-нибудь, как я, наткнется на это:

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

Это соответствует: «10-значный номер косой черты ничего-не-пробел»

Но для моего использования (просмотр HTML) это было нахождение ложноположительных результатов, поэтому я должен был соответствовать приведенному выше, плюс избавиться от кавычек и больше-меньше /: чем:

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

Я все еще проверяю их, но пока что чувствую надежду.

3 голосов
/ 24 апреля 2012

Вот мой пример:

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

И пара допустимых крайних случаев, когда это не дает сбоя, но другие, кажется, делают:

Кроме того, корректно отбрасывает некоторые ложные (X | HT) вещи ML, такие как:

  • <geo coords="10.4515260,51.1656910"></geo>
2 голосов
/ 16 июня 2014

Это действительно старый и ответ на вопрос, но вот еще одна потенциальная замена.

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

Предполагается, что пробел не является частью DOI.

Не проверял это на ложные срабатывания, но, похоже, он может найти все крайние случаи, упомянутые на этой странице.

0 голосов
/ 27 августа 2008

Следующее регулярное выражение должно выполнять эту работу (синтаксис регулярного выражения Perl):

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

Вы можете выполнить дополнительную проверку работоспособности, открыв URL

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

и

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

где кандидат дои,

и проверка того, что вы a) получаете статус http 200 OK и b) возвращенная страница не является страницей «DOI not found» для службы.

...