Поиск DOI в документе или на странице
Система DOI практически не накладывает никаких полезных ограничений на то, что составляет разумный идентификатор. Однако возможность извлекать DOI из PDF-файлов, веб-страниц и т. Д. Весьма полезна для информации о цитировании и т. Д.
Есть ли надежный способ идентифицировать DOI в блоке текста без использования префикса 'doi:'? (любой язык, приемлемый, предпочтение регулярных выражений и избегание ложных срабатываний обязательно)
7 ответов
Хорошо, в настоящее время я извлекаю тысячи 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';
И вот, вот демо.
У CrossRef есть рекомендация, чтобы они успешно прошли тестирование на 99,3% DOI:
/^10.\d{4,9}/[-._;()/:A-Z0-9]+$/i
@Silas Проверка работоспособности - хорошая идея. Тем не менее, регулярное выражение не охватывает все DOI. Первый элемент должен (в настоящее время) быть 10, а второй элемент должен (в настоящее время) быть числовым, но третий элемент практически не ограничен:
"Допустимые символы - это допустимые графические символы 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>
Следующее регулярное выражение должно выполнить работу (синтаксис регулярного выражения Perl):
/(10\.\d+\/\d+)/
Вы можете сделать дополнительную проверку здравомыслия, открыв URL
http://hdl.handle.net/<doi>
а также
http://dx.doi.org/<doi>
где кандидат дои,
и тестирование того, что вы a) получите статус HTTP 200 OK и b) возвращенная страница не является страницей "DOI not found" для службы.
Это действительно старый и ответ на вопрос, но вот еще одна потенциальная замена.
\b10\.(\d+\.*)+[\/](([^\s\.])+\.*)+\b
Это предполагает, что пустое пространство не является частью DOI.
Не проверяли это на ложные срабатывания, но, похоже, удалось найти все крайние случаи, упомянутые на этой странице.