Pergunta

O DOI sistema basicamente não coloca limitações úteis sobre o que constitui um identificador razoável.No entanto, ser capaz de extrair DOIs de PDFs, páginas da web, etc.é bastante útil para informações de citação, etc.

Existe uma maneira confiável de identificar um DOI em um bloco de texto sem assumir o prefixo ‘doi:’?(qualquer linguagem aceitável, regexes preferidas e evitando falsos positivos é obrigatório)

Foi útil?

Solução

Ok, atualmente estou extraindo milhares de DOIs de texto de formato livre (XML) e percebi que minha abordagem anterior tive alguns problemas, nomeadamente em relação às entidades codificadas e à pontuação final, por isso continuei a ler a especificação e isso é o melhor que eu poderia oferecer.


O prefixo doi deve ser composto por um indicador de diretório seguido por um código de registrante.Esses dois componentes devem ser separados por uma parada completa (período).

O indicador do diretório será “10”.O indicador de diretório distingue todo o conjunto de seqüências de caracteres (prefixo e sufixo) como identificadores de objetos digitais dentro do sistema de resolução.

Bastante fácil, o inicial \b nos impede de "corresponder" a um "DOI" que não comece com 10.:

$pattern = '\b(10[.]';

O segundo elemento do prefixo DOI será o código do registrante.O código do registrante é uma string exclusiva atribuída a um registrante.

Além disso, todos os códigos de registrante atribuídos são numéricos e têm pelo menos 4 dígitos, portanto:

$pattern = '\b(10[.][0-9]{4,}';

O Código do Registrante pode ser dividido em subelementos para conveniência administrativa, se desejar.Cada sub-elemento do Código do Registrante deve ser precedido por uma parada completa.

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*';

A sintaxe do DOI deve ser composta por um prefixo doi e um sufixo doi separado por uma barra para a frente.

No entanto, isso não é absolutamente necessário, a seção 2.2.3 afirma que sistemas de sufixos incomuns podem usar outras convenções (como 10.1000.123456 em vez de 10.1000/123456), mas vamos dar uma folga.

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/';

O nome do DOI é insensível a minúsculas e pode incorporar personagens imprimíveis dos caracteres gráficos legais do Unicode.O sufixo do DOI deve consistir em uma sequência de caráter de qualquer comprimento escolhido pelo registrante.Cada sufixo deve ser exclusivo do elemento prefixo que o precede.O sufixo exclusivo pode ser um número seqüencial, ou pode incorporar um identificador gerado ou baseado em outro sistema.

Agora é aqui que fica mais complicado, de todos os DOIs que processei, vi os seguintes caracteres (além [0-9a-zA-Z] é claro) em seus sufixos: .-()/:- -- então, embora não exista, o DOI 10.1016.12.31/nature.S0735-1097(98)2000/12/31/34:7-7 é completamente plausível.

A escolha lógica seria usar \S ou o [[:graph:]] Classe PCRE POSIX, então vamos fazer isso:

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/\S+'; // or
$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/[[:graph:]]+';

Agora temos um problema difícil, o [[:graph:]] class é um superconjunto do [[:punct:]] classe, que inclui caracteres facilmente encontrados em texto livre ou em qualquer linguagem de marcação: "'&<> entre outros.

Vamos apenas filtrar as marcações por enquanto usando um lookahead negativo:

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])\S)+'; // or
$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])[[:graph:]])+';

O acima deve cobrir entidades codificadas (&), aspas de atributos (["']) e tags de abertura/fechamento ([<>]).

Ao contrário das linguagens de marcação, o texto livre geralmente não utiliza caracteres de pontuação, a menos que sejam delimitados por pelo menos um espaço. ou colocado no final de uma frase, por exemplo:

Este é um DOI longo: 10.1016.12.31/nature.S0735-1097(98)2000/12/31/34:7-7!!!

A solução aqui é fechar nosso grupo de captura e afirmar outro limite de palavra:

$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])\S)+)\b'; // or
$pattern = '\b(10[.][0-9]{4,}(?:[.][0-9]+)*/(?:(?!["&\'<>])[[:graph:]])+)\b';

E voilá, aqui está uma demonstração.

Outras dicas

@Silas A verificação de sanidade é uma boa ideia.No entanto, a regex não cobre todos os DOIs.O primeiro elemento deve (atualmente) ser 10, e o segundo elemento deve (atualmente) ser numérico, mas o terceiro elemento é pouco restrito:

"Caracteres legais são os caracteres gráficos legais do Unicode.Isso exclui especificamente os intervalos de caracteres de controle 0x00-0x1F e 0x80-0x9F..."

e é aí que reside o verdadeiro problema.Na prática, nunca vi espaços em branco usados, mas a especificação permite isso especificamente.Basicamente, não parece haver uma maneira sensata de detectar o fim de um DOI.

CrossRef tem uma recomendação, que testaram com sucesso em 99,3% dos DOIs:

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

Tenho certeza de que não é muito útil para o OP neste momento, mas decidi postar o que estou tentando, caso alguém como eu se depare com isso:

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

Isso corresponde:"Barra de 10 pontos com qualquer coisa que não seja espaço em branco"

Mas para meu uso (raspagem de HTML), isso foi encontrar falsos positivos, então tive que corresponder ao acima, além de me livrar das aspas e maior que/menos que:

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

Ainda estou testando isso, mas estou esperançoso até agora.

Aqui está minha tentativa:

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

E alguns casos extremos válidos em que isso não falha, mas outros parecem falhar:

Além disso, descarta corretamente algumas coisas falsas (X|HT)ML como:

  • <geo coords="10.4515260,51.1656910"></geo>

Esta é uma pergunta muito antiga e respondida, mas aqui está outro substituto potencial.

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

Isso pressupõe que o espaço em branco não faz parte do DOI.

Não testei isso para falsos positivos, mas parece ser capaz de encontrar todos os casos extremos mencionados nesta página.

O seguinte regex deve fazer o trabalho (sintaxe Perl regex):

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

Você poderia fazer algumas verificações adicionais de integridade abrindo os URLs

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

e

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

onde está o candidato doi,

e testando se você a) obtém um status http 200 OK eb) a página retornada não é a página "DOI não encontrado" para o serviço.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top