Pregunta

El DOI El sistema básicamente no impone limitaciones útiles a lo que constituye un identificador razonable.Sin embargo, poder extraer DOI de archivos PDF, páginas web, etc.es bastante útil para información de citas, etc.

¿Existe una manera confiable de identificar un DOI en un bloque de texto sin asumir el prefijo 'doi:'?(cualquier idioma es aceptable, se prefieren las expresiones regulares y es imprescindible evitar falsos positivos)

¿Fue útil?

Solución

Ok, actualmente estoy extrayendo miles de DOI de texto de formato libre (XML) y me di cuenta de que mi enfoque anterior Tuve algunos problemas, concretamente con respecto a las entidades codificadas y la puntuación final, así que seguí leyendo la especificación y esto es lo mejor que pude encontrar.


El prefijo de DOI se compusirá de un indicador de directorio seguido de un código de registro.Estos dos componentes se separarán por una parada completa (período).

El indicador del directorio será "10".El indicador de directorio distingue todo el conjunto de cadenas de caracteres (prefijo y sufijo) como identificadores de objetos digitales dentro del sistema de resolución.

Bastante fácil, la inicial \b nos impide "hacer coincidir" un "DOI" que no comienza con 10.:

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

El segundo elemento del prefijo DOI será el código del registrante.El código de registro es una cadena única asignada a un registrante.

Además, todos los códigos de registrante asignados son numéricos y tienen al menos 4 dígitos, por lo que:

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

El Código de Registrante puede dividirse aún más en subelementos para conveniencia administrativa si lo desea.Cada subelemento del Código de Registrante estará precedido por una parada completa.

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

La sintaxis del DOI se compone de un prefijo DOI y un sufijo DOI separado por un corte hacia adelante.

Sin embargo, esto no es absolutamente necesario, la sección 2.2.3 establece que los sistemas de sufijos poco comunes pueden usar otras convenciones (como 10.1000.123456 en lugar de 10.1000/123456), pero seamos un poco más flexibles.

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

El nombre de DOI no es insensible al caso y puede incorporar cualquier caracteres imprimibles de los caracteres gráficos legales de Unicode.El sufijo DOI consistirá en una cadena de caracteres de cualquier longitud elegida por el registrante.Cada sufijo será exclusivo del elemento de prefijo que lo precede.El sufijo único puede ser un número secuencial, o puede incorporar un identificador generado o basado en otro sistema.

Ahora bien, aquí es donde se vuelve más complicado, de todos los DOI que he procesado, vi los siguientes caracteres (además de [0-9a-zA-Z] por supuesto) en su sufijos: .-()/:- -- entonces, aunque no exista, el DOI 10.1016.12.31/nature.S0735-1097(98)2000/12/31/34:7-7 es completamente plausible.

La elección lógica sería utilizar \S o el [[:graph:]] Clase PCRE POSIX, así que hagámoslo:

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

Ahora tenemos un problema difícil, el [[:graph:]] clase es un superconjunto de [[:punct:]] clase, que incluye caracteres que se encuentran fácilmente en texto libre o en cualquier lenguaje de marcado: "'&<> entre otros.

Filtremos los de marcado por ahora usando una búsqueda anticipada negativa:

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

Lo anterior debería cubrir entidades codificadas (&), comillas de atributos (["']) y abrir/cerrar etiquetas ([<>]).

A diferencia de los lenguajes de marcado, el texto libre generalmente no emplea caracteres de puntuación a menos que estén delimitados por al menos un espacio. o colocado al final de una oración, por ejemplo:

Este es un DOI largo: 10.1016.12.31/nature.S0735-1097(98)2000/12/31/34:7-7!!!

La solución aquí es cerrar nuestro grupo de captura y afirmar otro límite de palabras:

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

Y voilá, aquí hay una demostración.

Otros consejos

@Silas La comprobación de cordura es una buena idea.Sin embargo, la expresión regular no cubre todos los DOI.El primer elemento debe (actualmente) ser 10 y el segundo elemento debe (actualmente) ser numérico, pero el tercer elemento apenas tiene restricciones:

"Los caracteres legales son los caracteres gráficos legales de Unicode.Esto excluye específicamente los rangos de caracteres de control 0x00-0x1F y 0x80-0x9F..."

y ahí es donde radica el verdadero problema.En la práctica, nunca he visto que se utilicen espacios en blanco, pero la especificación lo permite específicamente.Básicamente, no parece haber una forma sensata de detectar el fin de un DOI.

CrossRef tiene una recomendación, que probaron con éxito en el 99,3% de los DOI:

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

Estoy seguro de que no es muy útil para el OP en este momento, pero pensé en publicar lo que estoy intentando en caso de que alguien como yo se tope con esto:

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

Esto coincide:"El número de 10 puntos corta todo lo que no sea espacio en blanco"

Pero para mi uso (raspar HTML), esto fue encontrar falsos positivos, así que tuve que hacer coincidir lo anterior, además de deshacerme de las comillas y mayor que/menor que:

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

Todavía los estoy probando, pero hasta ahora tengo esperanzas.

Aquí está mi intento:

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

Y un par de casos extremos válidos en los que esto no falla, pero otros parecen hacerlo:

Además, descarta correctamente algunas cosas falsas (X|HT)ML como:

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

Esta es una pregunta muy antigua y ya respondida, pero aquí hay otro posible sustituto.

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

Esto supone que el espacio en blanco no forma parte del DOI.

No lo he probado en busca de falsos positivos, pero parece poder encontrar todos los casos extremos mencionados en esta página.

La siguiente expresión regular debería hacer el trabajo (sintaxis de expresiones regulares de Perl):

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

Podrías realizar algunas comprobaciones adicionales de cordura abriendo las URL.

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

y

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

¿Dónde está el candidato Doi?

y comprobar que a) obtiene un estado http 200 OK y b) la página devuelta no es la página "DOI no encontrado" para el servicio.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top