VERO/js/checkPIDs.js
2026-03-04 10:12:09 +01:00

356 lines
11 KiB
JavaScript

/**
* Plausibilitätsprüfung von ISBN-10, ISBN-13, ISSN, Handle, DOI und URN
*/
/**
* Prüft eine ISBN-10 auf Plausibilität
* @param {string} isbn10 - Die zu prüfende ISBN-10
* @returns {boolean} - true wenn gültig, false wenn ungültig
*/
function validateISBN10(isbn10) {
if (!isbn10) return false;
// Normalisierung: Bindestriche und Leerzeichen entfernen
const clean = isbn10.replace(/[-\s]/g, '');
// Muss genau 10 Zeichen haben
if (clean.length !== 10) return false;
// Erste 9 Zeichen müssen Ziffern sein, letztes Zeichen Ziffer oder X
if (!/^\d{9}[\dX]$/.test(clean)) return false;
// Prüfziffer berechnen
let sum = 0;
for (let i = 0; i < 9; i++) {
sum += parseInt(clean[i]) * (10 - i);
}
const checkDigit = clean[9];
const calculatedCheck = (11 - (sum % 11)) % 11;
return (calculatedCheck === 10 && checkDigit === 'X') ||
(calculatedCheck < 10 && checkDigit === calculatedCheck.toString());
}
/**
* Prüft eine ISBN-13 auf Plausibilität
* @param {string} isbn13 - Die zu prüfende ISBN-13
* @returns {boolean} - true wenn gültig, false wenn ungültig
*/
function validateISBN13(isbn13) {
if (!isbn13) return false;
// Normalisierung: Bindestriche und Leerzeichen entfernen
const clean = isbn13.replace(/[-\s]/g, '');
// Muss genau 13 Ziffern haben
if (clean.length !== 13 || !/^\d{13}$/.test(clean)) return false;
// Muss mit 978 oder 979 beginnen
if (!clean.startsWith('978') && !clean.startsWith('979')) return false;
// Prüfziffer berechnen (modulo 10)
let sum = 0;
for (let i = 0; i < 12; i++) {
sum += parseInt(clean[i]) * (i % 2 === 0 ? 1 : 3);
}
const checkDigit = parseInt(clean[12]);
const calculatedCheck = (10 - (sum % 10)) % 10;
return checkDigit === calculatedCheck;
}
/**
* Prüft einen DOI auf Plausibilität
* @param {string} doi - Der zu prüfende DOI
* @returns {boolean} - true wenn gültig, false wenn ungültig
*/
function validateDOI(doi) {
if (!doi) return false;
// DOI kann mit oder ohne "doi:" Präfix sein
const clean = doi.replace(/^doi:\s*/i, '');
// Grundlegendes DOI-Format: 10.xxxx/yyyy
// Registrant Code muss mit 10. beginnen
const doiRegex = /^10\.\d{4,}\/[^\s]+$/;
if (!doiRegex.test(clean)) return false;
// Weitere Plausibilitätsprüfungen
const parts = clean.split('/');
if (parts.length < 2) return false;
const prefix = parts[0];
const suffix = parts.slice(1).join('/');
// Präfix muss 10.xxxx Format haben (mindestens 4 Ziffern nach 10.)
if (!/^10\.\d{4,}$/.test(prefix)) return false;
// Suffix darf nicht leer sein und keine Leerzeichen enthalten
if (!suffix.trim() || /\s/.test(suffix)) return false;
return true;
}
/**
* Prüft eine URN auf Plausibilität
* @param {string} urn - Die zu prüfende URN
* @returns {boolean} - true wenn gültig, false wenn ungültig
*/
function validateURN(urn) {
if (!urn) return false;
// URN muss mit "urn:" beginnen (case-insensitive)
if (!urn.toLowerCase().startsWith('urn:')) return false;
// Grundlegendes URN-Format: urn:namespace:identifier
const parts = urn.split(':');
if (parts.length < 3) return false;
const namespace = parts[1];
const identifier = parts.slice(2).join(':');
// Namespace-Validierung
if (!namespace || !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(namespace)) {
return false;
}
// Namespace darf nicht länger als 32 Zeichen sein
if (namespace.length > 32) return false;
// Identifier darf nicht leer sein
if (!identifier) return false;
// Prüfung auf reservierte Zeichen (vereinfacht)
const reservedChars = /[<>"{}|\\^`\[\]]/;
if (reservedChars.test(identifier)) return false;
return true;
}
/**
* Prüft eine ISSN auf Plausibilität
* @param {string} issn - Die zu prüfende ISSN
* @returns {boolean} - true wenn gültig, false wenn ungültig
*/
function validateISSN(issn) {
if (!issn) return false;
// Normalisierung: Bindestriche und Leerzeichen entfernen
const clean = issn.replace(/[-\s]/g, '');
// Muss genau 8 Zeichen haben
if (clean.length !== 8) return false;
// Erste 7 Zeichen müssen Ziffern sein, letztes Zeichen Ziffer oder X
if (!/^\d{7}[\dX]$/.test(clean)) return false;
// Prüfziffer berechnen (modulo 11)
let sum = 0;
for (let i = 0; i < 7; i++) {
sum += parseInt(clean[i]) * (8 - i);
}
const checkDigit = clean[7];
const calculatedCheck = (11 - (sum % 11)) % 11;
return (calculatedCheck === 10 && checkDigit === 'X') ||
(calculatedCheck < 10 && checkDigit === calculatedCheck.toString());
}
/**
* Prüft eine eISSN (elektronische ISSN) auf Plausibilität
* @param {string} eissn - Die zu prüfende eISSN
* @returns {boolean} - true wenn gültig, false wenn ungültig
*/
function validateEISSN(eissn) {
// eISSN hat das gleiche Format wie ISSN
return validateISSN(eissn);
}
/**
* Validierung verschiedener Identifier-Typen
* @param {string} identifier - Der zu prüfende Identifier
* @param {string} identifierType - Identifier Typ ("ISBN" | "ISSN" | "URN" | "DOI" | "Handle")
* @returns {object} - Objekt mit Typ und Validierungsergebnis
*/
function validateIdentifier(identifier, identifierType) {
if (!identifier) {
return { type: 'unknown', valid: false, error: 'Leerer Identifier' };
}
const clean = identifier.trim();
switch (identifierType) {
case "URN": return {
type: 'URN',
valid: validateURN(clean),
identifier: clean
};
case "DOI": if (clean.toLowerCase().startsWith('doi:') || clean.startsWith('10.')) {
return {
type: 'DOI',
valid: validateDOI(clean),
identifier: clean
};
}
case "ISBN": const isbnClean = clean.replace(/[-\s]/g, '');
if (/^\d{10}$/.test(isbnClean) || /^\d{9}X$/.test(isbnClean)) {
return {
type: 'ISBN-10',
valid: validateISBN10(clean),
identifier: clean
};
}
if (/^\d{13}$/.test(isbnClean)) {
return {
type: 'ISBN-13',
valid: validateISBN13(clean),
identifier: clean
};
}
case "ISSN": const issnClean = clean.replace(/[-\s]/g, '');
if (/^\d{8}$/.test(issnClean) || /^\d{7}X$/.test(issnClean)) {
return {
type: 'ISSN',
valid: validateISSN(clean),
identifier: clean
};
}
case "Handle":if (clean.toLowerCase().startsWith('hdl:') ||
clean.toLowerCase().includes('hdl.handle.net') ||
clean.toLowerCase().includes('handle.net') ||
/^\d+(\.\d+)*\//.test(clean)) {
return {
type: 'Handle',
valid: validateHandle(clean),
identifier: clean
};
}
default: return { type: 'Identifikator unbekannt: Struktur ist kein DOI, keine URN, ISBN, ISSN oder Handle', valid: false, error: 'Bitte prüfen Sie den gewählten Identifikator und dessen Inhalt (z.B DOI: 10.1515/zfsoz-2025-2017, URN: urn:nbn:de:0035-vetrepository-783215)' };
}
}
/**
* Hilfsfunktion: Normalisiert ISBN-Eingaben
* @param {string} isbn - ISBN mit oder ohne Trennzeichen
* @returns {string} - Normalisierte ISBN ohne Trennzeichen
*/
function normalizeISBN(isbn) {
return isbn ? isbn.replace(/[-\s]/g, '') : '';
}
/**
* Hilfsfunktion: Extrahiert DOI ohne Präfix
* @param {string} doi - DOI mit oder ohne "doi:" Präfix
* @returns {string} - DOI ohne Präfix
*/
function normalizeDOI(doi) {
return doi ? doi.replace(/^doi:\s*/i, '') : '';
}
/**
* Batch-Validierung für mehrere Identifier
* @param {string[]} identifiers - Array von zu prüfenden Identifiern
* @returns {object[]} - Array von Validierungsergebnissen
*/
function validateMultipleIdentifiers(identifiers) {
if (!Array.isArray(identifiers)) {
return [];
}
return identifiers.map(id => validateIdentifier(id));
}
/**
* Prüft ob ein String eine gültige ISBN (10 oder 13) ist
* @param {string} isbn - Zu prüfende ISBN
* @returns {boolean} - true wenn gültige ISBN-10 oder ISBN-13
*/
function isValidISBN(isbn) {
return validateISBN10(isbn) || validateISBN13(isbn);
}
function validateHandle(handle) {
if (!handle) return false;
// Handle kann mit oder ohne "hdl:" Präfix oder "http://hdl.handle.net/" sein
let clean = handle.trim();
// Verschiedene Handle-Präfixe entfernen
clean = clean.replace(/^hdl:\s*/i, '');
clean = clean.replace(/^https?:\/\/hdl\.handle\.net\//, '');
clean = clean.replace(/^https?:\/\/handle\.net\//, '');
// Handle-Format: prefix/suffix (z.B. 10.1000/123 oder 1721.1/12345)
if (!clean.includes('/')) return false;
const parts = clean.split('/');
if (parts.length < 2) return false;
const prefix = parts[0];
const suffix = parts.slice(1).join('/');
// Prefix-Validierung
if (!prefix || prefix.length === 0) return false;
// Prefix darf nur Zahlen, Punkte und Bindestriche enthalten
if (!/^[0-9.-]+$/.test(prefix)) return false;
// Suffix-Validierung
if (!suffix || suffix.length === 0) return false;
// Suffix darf keine Leerzeichen enthalten
if (/\s/.test(suffix)) return false;
// Reservierte Zeichen prüfen
const reservedChars = /[<>"{}|\\^`\[\]]/;
if (reservedChars.test(suffix)) return false;
return true;
}
// ========================================
// Beispiele für die Verwendung
// ========================================
/* console.log('=== ISBN-10 Tests ===');
console.log('0-306-40615-2:', validateISBN10('0-306-40615-2')); // true
console.log('0306406152:', validateISBN10('0306406152')); // true
console.log('0306406151:', validateISBN10('0306406151')); // false
console.log('0-19-852663-6:', validateISBN10('0-19-852663-6')); // true
console.log('\n=== ISBN-13 Tests ===');
console.log('978-0-306-40615-7:', validateISBN13('978-0-306-40615-7')); // true
console.log('9780306406157:', validateISBN13('9780306406157')); // true
console.log('9780306406156:', validateISBN13('9780306406156')); // false
console.log('979-0-000-00000-0:', validateISBN13('979-0-000-00000-0')); // true
console.log('\n=== DOI Tests ===');
console.log('10.1000/182:', validateDOI('10.1000/182')); // true
console.log('doi:10.1000/182:', validateDOI('doi:10.1000/182')); // true
console.log('10.1038/nature12373:', validateDOI('10.1038/nature12373')); // true
console.log('10.123/456:', validateDOI('10.123/456')); // false (zu kurz)
console.log('\n=== URN Tests ===');
console.log('urn:isbn:0451450523:', validateURN('urn:isbn:0451450523')); // true
console.log('urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66:', validateURN('urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66')); // true
console.log('urn:nbn:de:bvb:19-146642:', validateURN('urn:nbn:de:bvb:19-146642')); // true
console.log('not-a-urn:', validateURN('not-a-urn')); // false
console.log('\n=== Hilfsfunktionen ===');
console.log('Normalisierte ISBN:', normalizeISBN('978-0-306-40615-7'));
console.log('Normalisierter DOI:', normalizeDOI('doi:10.1000/182'));
console.log('Gültige ISBN?:', isValidISBN('978-0-306-40615-7'));
*/