Eine freie Initiative von Menschen bei anthrowiki.at, anthro.world, biodyn.wiki und steiner.wiki mit online Lesekreisen, Übungsgruppen, Vorträgen ... |
Wie Sie die Entwicklung von AnthroWiki durch Ihre Spende unterstützen können, erfahren Sie hier. |
Use Google Translate for a raw translation of our pages into more than 100 languages. Please note that some mistranslations can occur due to machine translation. |
Li Livres Dou Trésor und Modul:URIutil: Unterschied zwischen den Seiten
Aus AnthroWiki
(Unterschied zwischen Seiten)
imported>Odyssee |
imported>Odyssee (Die Seite wurde neu angelegt: „local URIutil = { suite = "URIutil", serial = "2017-10-04" }; --[=[ Utilities for URI etc. * coreISSN() * formatISBN() * formatISSN() * form…“) |
||
Zeile 1: | Zeile 1: | ||
[[ | local URIutil = { suite = "URIutil", | ||
serial = "2017-10-04" }; | |||
--[=[ | |||
Utilities for URI etc. | |||
* coreISSN() | |||
* formatISBN() | |||
* formatISSN() | |||
* formatLCCN() | |||
* isDNBvalid() | |||
* isDOI() | |||
* isEscValid() | |||
* isGTINvalid() | |||
* isHandle() | |||
* isISBN() | |||
* isISBNvalid() | |||
* isISSNvalid() | |||
* isLCCN() | |||
* linkDNBopac() | |||
* linkDOI() | |||
* linkHandle() | |||
* linkISBN() | |||
* linkISSN() | |||
* linkLCCN() | |||
* linkURN() | |||
* mayDOI() | |||
* mayHandle() | |||
* mayISBN() | |||
* mayISSN() | |||
* mayLCCN() | |||
* mayURI() | |||
* mayURN() | |||
* plainISBN() | |||
* targetISSN() | |||
* uriDOI() | |||
* uriHandle() | |||
* uriURN() | |||
* failsafe() | |||
* URIutil() | |||
loadData: URIutil/config URIutil/isbn URIutil/urn | |||
]=] | |||
local CurrentPageName | |||
local factory = function ( attempt, allowX ) | |||
-- Retrieve plain digits of attempt | |||
-- Precondition: | |||
-- attempt -- string; with digits (+xX) and hyphens, not trimmed | |||
-- allowX -- number; of (last) position for permitted xX | |||
-- boolean; xX at last position permitted | |||
-- Postcondition: | |||
-- Returns table; success | |||
-- [1]...[8]/[10]...[13] -- digits 0...9 | |||
-- 10 at last position | |||
-- .hyphens -- number of hyphens | |||
-- .type -- number of digits | |||
-- number; no string or bad length or data | |||
-- 0 -- no string | |||
-- >0 -- unexpected char at position (trimmed) | |||
local r; | |||
if type( attempt ) == "string" then | |||
local c, i; | |||
local j = 0; | |||
local k = 1; | |||
local s = mw.text.trim( attempt ); | |||
local n = mw.ustring.len( s ); | |||
r = { hyphens = 0 }; | |||
for i = 1, n do | |||
c = mw.ustring.codepoint( s, i, i + 1 ); | |||
if c >= 48 and c <= 57 then | |||
j = j + 1; | |||
r[ j ] = c - 48; | |||
k = false; | |||
elseif c == 45 then -- hyphen | |||
if i > 1 and i < n then | |||
r.hyphens = r.hyphens + 1; | |||
k = i; | |||
else | |||
r = j; | |||
break; | |||
end | |||
elseif c == 88 or c == 120 then -- X x | |||
j = j + 1; | |||
if allowX and i == n then | |||
if allowX == true or allowX == j then | |||
r[ j ] = 10; | |||
else | |||
r = j; | |||
end | |||
else | |||
r = j; | |||
end | |||
break; | |||
else | |||
r = j; | |||
break; | |||
end | |||
end -- for i | |||
if type( r ) == "table" then | |||
r.type = j; | |||
end | |||
else | |||
r = 0; | |||
end | |||
return r; | |||
end -- factory() | |||
local faculty = function ( ask, auto ) | |||
-- Evaluate possible string as boolean signal, if brief | |||
-- Precondition: | |||
-- ask -- trimmed string or nil or other | |||
-- auto -- fallback value if nil | |||
-- Postcondition: | |||
-- Returns appropriate value, or ask | |||
local r; | |||
if type( ask ) == "string" then | |||
if ask == "1" or ask == "" then | |||
r = true; | |||
elseif ask == "0" or ask == "-" then | |||
r = false; | |||
else | |||
r = ask; | |||
end | |||
elseif ask == nil then | |||
r = auto; | |||
else | |||
r = ask; | |||
end | |||
return r; | |||
end -- faculty() | |||
== | local fair = function ( assert ) | ||
-- Compute check digit (11 minus modulo 11) for descending factor | |||
-- Precondition: | |||
-- assert -- table; as of factory() | |||
-- .type -- number of digits including check digit | |||
-- Postcondition: | |||
-- Returns checksum | |||
local i; | |||
local n = assert.type; | |||
local k = n; | |||
local r = 0; | |||
for i = 1, n - 1 do | |||
r = r + k * assert[ i ]; | |||
k = k - 1; | |||
end -- for i | |||
return ( 11 - r % 11 ); | |||
end -- fair() | |||
[[ | |||
local function fault( alert ) | |||
-- Format error message by class=error | |||
-- Parameter: | |||
-- alert -- string, error message | |||
-- Returns: | |||
-- string, HTML span | |||
return string.format( "<span class=\"error\">%s</span>", alert ); | |||
end -- fault() | |||
local fetch = function ( acquire ) | |||
-- Load data submodule | |||
-- Precondition: | |||
-- acquire -- string, one of | |||
-- "config" | |||
-- "isbn" | |||
-- "urn" | |||
-- Postcondition: | |||
-- Returns any table | |||
local r; | |||
if URIutil.data then | |||
r = URIutil.data[ acquire ]; | |||
else | |||
URIutil.data = { }; | |||
end | |||
if not r then | |||
local lucky; | |||
lucky, r = pcall( mw.loadData, "Module:URIutil/" .. acquire ); | |||
if type( r ) ~= "table" then | |||
r = { }; | |||
end | |||
URIutil.data[ acquire ] = r; | |||
end | |||
return r; | |||
end -- fetch() | |||
local flop = function ( alert ) | |||
-- Create link to (maintenance) category | |||
-- Precondition: | |||
-- alert -- trimmed string with title, not empty, or nil | |||
-- Postcondition: | |||
-- Returns link, or false | |||
local r; | |||
if type( alert ) == "string" and alert ~= "" then | |||
r = string.format( "[[Category:%s]]", alert ); | |||
end | |||
return r; | |||
end -- flop() | |||
local format = function ( assigned, ahead, amount ) | |||
-- Convert part of digit sequence into string | |||
-- Precondition: | |||
-- assigned -- table; as of factory() | |||
-- ahead -- index of first digit | |||
-- amount -- number of digits to append | |||
-- Postcondition: | |||
-- Returns string with digits and hyphens | |||
local i, k; | |||
local r = ""; | |||
for i = ahead, ahead + amount - 1 do | |||
k = assigned[ i ]; | |||
if k == 10 then | |||
r = r .. "X"; | |||
else | |||
r = r .. tostring( k ); | |||
end | |||
end -- for i | |||
return r; | |||
end -- format() | |||
local fullPageName = function () | |||
-- Retrieve current page name | |||
-- Postcondition: | |||
-- Returns string: current page name | |||
if not CurrentPageName then | |||
CurrentPageName = mw.title.getCurrentTitle().fullText; | |||
end | |||
return CurrentPageName; | |||
end -- fullPageName() | |||
local DNBfaith = function ( assert, ancestor ) | |||
-- Compute DNB (also GND, ZDB) check digit and verify | |||
-- Precondition: | |||
-- assert -- table; as of factory() | |||
-- .type -- until 11 including check digit | |||
-- ancestor -- true: 2011 mode | |||
-- Postcondition: | |||
-- Returns true: check digit matches | |||
-- 2013-09-01 | |||
local k = fair( assert ) % 11; | |||
if ancestor then | |||
k = 11 - k; | |||
end | |||
return ( k == assert[ assert.type ] ); | |||
end -- DNBfaith() | |||
local GTINfair = function ( assert ) | |||
-- Compute GTIN check digit | |||
-- Precondition: | |||
-- assert -- table; ~ 13 digits | |||
-- .type -- 13 ... | |||
-- Postcondition: | |||
-- Returns number 0...9 | |||
local i, k; | |||
local lead = true; | |||
local r = 0; | |||
for i = 1, assert.type - 1 do | |||
k = assert[ i ]; | |||
r = r + k; | |||
if lead then -- odd | |||
lead = false; | |||
else -- even | |||
r = r + k + k; | |||
lead = true; | |||
end | |||
end -- for i | |||
r = (10 - r % 10) % 10; | |||
return r; | |||
end -- GTINfair() | |||
local GTINfaith = function ( assert ) | |||
-- Compute GTIN check digit and verify | |||
-- Precondition: | |||
-- assert -- table; ~ 13 digits | |||
-- .type -- 13 ... | |||
-- Postcondition: | |||
-- Returns true: check digit matches | |||
return ( GTINfair( assert ) == assert[ assert.type ] ); | |||
end -- GTINfaith() | |||
local ISBNfactory = function ( attempt ) | |||
-- Retrieve plain digits of ISBN attempt | |||
-- Precondition: | |||
-- attempt -- string with digits (+xX) and hyphens, not trimmed | |||
-- Postcondition: | |||
-- Returns table; success | |||
-- [1]...[13] -- digits 0...9 | |||
-- 10 at ISBN-10 last position | |||
-- .type -- 10 or 13 | |||
-- .hyphens -- 0... number of hyphens | |||
-- number; no string or bad length or data | |||
-- 0 -- no string | |||
-- >0 -- unexpected char at position (trimmed) | |||
-- -1 -- bad digit count | |||
-- -2 -- bad bookland | |||
local r; | |||
if type( attempt ) == "string" then | |||
local s; | |||
r = factory( attempt, 10 ); | |||
s = type( r ); | |||
if s == "number" and r ~= 10 and r > 6 and r < 13 then | |||
r = factory( attempt, r ); | |||
s = type( r ); | |||
end | |||
if s == "table" then | |||
if r.type == 13 then | |||
if r[1] ~= 9 or | |||
r[2] ~= 7 or | |||
r[3] < 8 then | |||
r = -2; | |||
end | |||
elseif r.type ~= 10 then | |||
r = -1; | |||
end | |||
end | |||
else | |||
r = 0; | |||
end | |||
return r; | |||
end -- ISBNfactory() | |||
local ISBNfaith = function ( assert ) | |||
-- Compute ISBN check digit and verify | |||
-- Precondition: | |||
-- assert -- table; as of ISBNfactory() | |||
-- .type -- 10 or 13 | |||
-- Postcondition: | |||
-- Returns true: check digit matches | |||
local r; | |||
if assert.type == 10 then | |||
local i; | |||
local k = 0; | |||
for i = 1, 9 do | |||
k = k + i * assert[ i ]; | |||
end -- for i | |||
k = k % 11; | |||
r = ( k == assert[ 10 ] ); | |||
elseif assert.type == 13 then | |||
r = GTINfaith( assert ); | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- ISBNfaith() | |||
local ISBNflat = function ( assigned ) | |||
-- Plain digits of attempt ISBN | |||
-- Precondition: | |||
-- assigned -- table; as of ISBNfactory() | |||
-- Postcondition: | |||
-- Returns string with digits; ISBN-10 with 'X' at last position | |||
local i; | |||
local r = ""; | |||
local n = assigned.type; | |||
if n == 10 then | |||
if assigned[ assigned.type ] == 10 then | |||
n = 9; | |||
end | |||
end | |||
for i = 1, n do | |||
r = r .. tostring( assigned[ i ] ); | |||
end -- for i | |||
if n == 9 then | |||
r = r .. "X"; | |||
end | |||
return r; | |||
end -- ISBNflat() | |||
local ISBNfold = function ( assigned, apply, allocate, already ) | |||
-- Retrieve number of digits for ISBN publisher/group | |||
-- Precondition: | |||
-- assigned -- table; as of ISBNfactory() | |||
-- apply -- number; of bookland (978 or 979) | |||
-- allocate -- number; of country | |||
-- already -- number; position in assigned to inspect | |||
-- Postcondition: | |||
-- Returns number of digits, at least 0 | |||
local r = 0; | |||
local def = fetch( "isbn" ); | |||
local bookland = def[ apply ]; | |||
if type( bookland ) == "table" then | |||
local country = bookland[ allocate ]; | |||
if type( country ) == "table" then | |||
local e, i, j, k, m, v; | |||
for i = 1, 4 do | |||
v = country[ i ]; | |||
if type( v ) == "table" then | |||
m = tonumber( format( assigned, already, i ) ); | |||
for k, e in pairs( v ) do | |||
if m >= e[ 1 ] and m <= e[ 2 ] then | |||
r = e[ 3 ]; | |||
break; -- for k | |||
end | |||
end -- for k | |||
end | |||
if r > 0 then | |||
break; -- for i | |||
end | |||
end -- for i | |||
end | |||
end | |||
return r; | |||
end -- ISBNfold() | |||
local ISBNformat = function ( attempt, assigned ) | |||
-- Hyphen formatting; at least try minimum | |||
-- Precondition: | |||
-- attempt -- string with presumable ISBN | |||
-- assigned -- table; as of ISBNfactory() | |||
-- .type -- 10 or 13 | |||
-- .hyphens -- 0...4 | |||
-- Postcondition: | |||
-- Returns string with digits and hyphens | |||
local r = false; | |||
local j, k, m, n; | |||
if assigned.type == 10 then | |||
m = 978; | |||
r = ""; | |||
j = 1; | |||
else | |||
m = 970 + assigned[ 3 ]; | |||
r = tostring( m ) .. "-"; | |||
j = 4; | |||
end | |||
if assigned[ j ] < 8 then | |||
k = 1; | |||
else | |||
k = 2; | |||
if assigned[ j ] == 9 and | |||
assigned[ j + 1 ] > 4 then | |||
k = 3; | |||
if assigned[ j + 1 ] > 8 then | |||
k = 4; | |||
if assigned[ j + 2 ] > 8 then | |||
k = 5; | |||
end | |||
end | |||
end | |||
end | |||
if k then | |||
n = format( assigned, j, k ); | |||
r = string.format( "%s%s-", r, n ); | |||
j = j + k; | |||
n = ISBNfold( assigned, m, tonumber( n ), j ); | |||
if n > 0 then | |||
r = string.format( "%s%s-", r, format( assigned, j, n ) ); | |||
j = j + n; | |||
end | |||
end | |||
r = r .. format( assigned, j, assigned.type - j ); | |||
if assigned[ assigned.type ] == 10 then | |||
r = r .. "-X"; | |||
else | |||
r = string.format( "%s-%s", | |||
r, | |||
tostring( assigned[ assigned.type ] ) ); | |||
end | |||
if not r then | |||
r = mw.ustring.upper( mw.text.trim( attempt ) ); | |||
end | |||
return r; | |||
end -- ISBNformat() | |||
local ISSNfactory = function ( attempt ) | |||
-- Retrieve plain digits of ISSN attempt | |||
-- Precondition: | |||
-- attempt -- string with digits (+xX) and hyphens, not trimmed | |||
-- Postcondition: | |||
-- Returns table; success | |||
-- [1]...[13] -- digits 0...9 | |||
-- 10 at ISSN-8 last position | |||
-- .type -- 8 or 13 | |||
-- .hyphens -- 0... number of hyphens | |||
-- number; no string or bad length or data | |||
-- 0 -- no string | |||
-- >0 -- unexpected char at position (trimmed) | |||
-- -1 -- bad digit count | |||
-- -2 -- bad issnland | |||
local r; | |||
if type( attempt ) == "string" then | |||
r = factory( attempt, 8 ); | |||
if type( r ) == "table" then | |||
if r.type == 13 then | |||
if r[1] ~= 9 or | |||
r[2] ~= 7 or | |||
r[3] ~= 7 then | |||
r = -2; | |||
end | |||
elseif r.type ~= 8 then | |||
r = -1; | |||
end | |||
end | |||
else | |||
r = 0; | |||
end | |||
return r; | |||
end -- ISSNfactory() | |||
local ISSNfaith = function ( assert ) | |||
-- Compute ISSN check digit and verify | |||
-- Precondition: | |||
-- assert -- table; as of ISSNfactory() | |||
-- .type -- 8 or 13 | |||
-- Postcondition: | |||
-- Returns true: check digit matches | |||
local r; | |||
if assert.type == 8 then | |||
local k = fair( assert ); | |||
if k == 11 then | |||
r = ( assert[ 8 ] == 0 ); | |||
else | |||
r = ( assert[ 8 ] == k ); | |||
end | |||
elseif assert.type == 13 then | |||
r = GTINfaith( assert ); | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- ISSNfaith() | |||
local ISSNformat = function ( assigned, achieve ) | |||
-- Hyphen formatting of ISSN | |||
-- Precondition: | |||
-- assigned -- table; as of ISSNfactory(), and valid | |||
-- achieve -- 8 or 13 | |||
-- Postcondition: | |||
-- Returns string with digits and hyphens | |||
local r; | |||
if achieve == 8 then | |||
local x; | |||
if assigned.type == 8 then | |||
r = string.format( "%s-%s", | |||
format( assigned, 1, 4 ), | |||
format( assigned, 5, 3 ) ); | |||
x = assigned[ 8 ]; | |||
elseif assigned.type == 13 then | |||
r = string.format( "%s-%s", | |||
format( assigned, 4, 4 ), | |||
format( assigned, 8, 3 ) ); | |||
x = fair( assigned ); | |||
end | |||
if x == 10 then | |||
r = r .. "X"; | |||
else | |||
r = r .. tostring( x ); | |||
end | |||
elseif achieve == 13 then | |||
if assigned.type == 8 then | |||
r = string.format( "977-%s-00-%s", | |||
format( assigned, 1, 7 ), | |||
GTINfair( assigned ) ); | |||
elseif assigned.type == 13 then | |||
r = string.format( "977-%s%s-%s", | |||
format( assigned, 4, 7 ), | |||
format( assigned, 10, 2 ), | |||
tostring( assigned[ 13 ] ) ); | |||
end | |||
end | |||
return r; | |||
end -- ISSNformat() | |||
local LCCNfactory = function ( attempt, allow ) | |||
-- Retrieve segments of LCCN attempt (format since 2001) | |||
-- Precondition: | |||
-- attempt -- string with presumable LCCN | |||
-- allow -- false or string: "/" | |||
-- Postcondition: | |||
-- Returns table; success | |||
-- false if not correct, bad data | |||
-- 2014-12-28 | |||
local r = false; | |||
local pat = "^%s*(%a*)(/?)(%d%S+)%s*$"; | |||
local pre, sep, s = attempt:match( pat ); | |||
if pre and s then | |||
local year, serial; | |||
if pre == "" then | |||
pre = false; | |||
if sep ~= "" then | |||
s = false; | |||
end | |||
elseif #pre > 3 then | |||
s = false; | |||
else | |||
pre = pre:lower(); | |||
end | |||
if s then | |||
if allow ~= "/" or sep == "/" then | |||
if sep == "/" then | |||
year, serial = s:match( "^(%d+)/(%d.+)$" ); | |||
elseif s:find( "-", 2, true ) then | |||
year, serial = s:match( "^(%d+)%-(%d.+)$" ); | |||
else | |||
year = s:match( "^([%d]+)" ); | |||
if year then | |||
if #year <= 8 then | |||
year = s:sub( 1, 2 ); | |||
serial = s:sub( 3 ); | |||
elseif #year <= 10 then | |||
year = s:sub( 1, 4 ); | |||
serial = s:sub( 5 ); | |||
else | |||
year = false; | |||
serial = s; | |||
end | |||
elseif tonumber( s ) then | |||
serial = s; | |||
end | |||
end | |||
end | |||
if year then | |||
if #year == 4 then | |||
local n = tonumber( year ); | |||
if n <= 2000 then | |||
-- 2000 -> "00" | |||
serial = false; | |||
elseif n > tonumber( os.date( "%Y" ) ) then | |||
serial = false; | |||
end | |||
elseif #year ~= 2 then | |||
serial = false; | |||
end | |||
end | |||
if serial then | |||
r = { pre = pre, serial = serial }; | |||
if year then | |||
r.year = year; | |||
end | |||
if serial:find( "/", 2, true ) then | |||
local q; | |||
serial, q = serial:lower() | |||
:match( "^(%d+)/([a-z]+)$" ); | |||
if q == "dc" or | |||
q == "mads" or | |||
q == "marcxml" or | |||
q == "mods" then | |||
r.serial = serial; | |||
r.qualifier = q; | |||
end | |||
end | |||
if serial then | |||
serial = serial:match( "^0*([1-9]%d*)$" ); | |||
end | |||
if not serial then | |||
r = false; | |||
elseif #serial < 6 then | |||
r.serial = string.format( "%06d", | |||
tonumber( serial ) ); | |||
elseif #serial > 6 then | |||
r = false; | |||
end | |||
end | |||
end | |||
end | |||
return r; | |||
end -- LCCNfactory() | |||
local LCCNformat = function ( assigned, achieve ) | |||
-- Standard or hyphen or slash formatting of LCCN | |||
-- Precondition: | |||
-- assigned -- table; as of LCCNfactory(), and valid | |||
-- achieve -- additional formatting desires, like "-" or "/" | |||
-- Postcondition: | |||
-- Returns string with letters, digits and hyphens | |||
-- 2013-07-14 | |||
local r; | |||
if assigned.pre then | |||
r = assigned.pre; | |||
else | |||
r = ""; | |||
end | |||
if assigned.year then | |||
if achieve == "/" and r ~= "" then | |||
r = r .. "/"; | |||
end | |||
r = r .. assigned.year; | |||
if achieve then | |||
r = r .. achieve; | |||
end | |||
end | |||
if assigned.serial then | |||
r = r .. assigned.serial; | |||
end | |||
if assigned.qualifier then | |||
r = string.format( "%s/%s", r, assigned.qualifier ); | |||
end | |||
return r; | |||
end -- LCCNformat() | |||
local LCCNforward = function ( attempt, achieve ) | |||
-- Retrieve bracketed titled external LCCN permalink | |||
-- Precondition: | |||
-- attempt -- string with presumable LCCN | |||
-- achieve -- additional title formatting desires, like "-" | |||
-- Postcondition: | |||
-- Returns link, or plain attempt if bad LCCN | |||
-- 2015-08-10 | |||
local lccn = LCCNfactory( attempt ); | |||
local r; | |||
if lccn then | |||
r = LCCNformat( lccn, false ); | |||
if r then | |||
local s; | |||
if achieve then | |||
s = LCCNformat( lccn, achieve ); | |||
else | |||
s = r; | |||
end | |||
r = string.format( "[//lccn.loc.gov/%s %s]", r, s ); | |||
end | |||
else | |||
r = attempt; | |||
end | |||
return r; | |||
end -- LCCNforward() | |||
local URNnamespace = function ( area, acquire ) | |||
-- Are these parts of a correct URN? | |||
-- Precondition: | |||
-- area -- string with lowercase namespace | |||
-- acquire -- string with identification | |||
-- Postcondition: | |||
-- Returns false if no problem detected | |||
-- string with violation | |||
local s = fetch( "urn" ).sns; | |||
local r; | |||
if type( s ) == "string" then | |||
r = string.format( ":%s:", area ); | |||
if s:match( r ) then | |||
s = "[^%w%(%)%+,%-%.:=@;%$_!%*'].*$"; | |||
r = acquire:match( s ); | |||
else | |||
r = string.format( ":%s:", area ); | |||
end | |||
if not r then | |||
r = false; | |||
if area == "isbn" then | |||
if not URIutil.isISBNvalid( acquire ) then | |||
r = acquire; | |||
end | |||
elseif area == "issn" then | |||
if not URIutil.isISSNvalid( acquire ) then | |||
r = acquire; | |||
end | |||
end | |||
end | |||
end | |||
return r; | |||
end -- URNnamespace() | |||
local URNresolve = function ( assigned, ask, alter ) | |||
-- Resolve URN within space | |||
-- Precondition: | |||
-- assigned -- table with resolvers for this space | |||
-- ask -- string with ID within this space | |||
-- alter -- string with alternative resolver, or not | |||
-- Postcondition: | |||
-- Returns | |||
-- 1. URL of resolver, or nil | |||
-- 2. modified ask | |||
local resolver = assigned; | |||
local sign = ask; | |||
local subset = assigned[ ":" ]; | |||
local r; | |||
if subset then | |||
local s = sign:match( subset ); | |||
if s then | |||
s = s:lower(); | |||
sign = s .. sign:sub( #s + 1 ) | |||
if assigned[ s ] then | |||
resolver = assigned[ s ]; | |||
end | |||
end | |||
end | |||
if alter then | |||
r = resolver[ alter ]; | |||
end | |||
if not r then | |||
r = resolver[ "*" ]; | |||
end | |||
return r, sign; | |||
end -- URNresolve() | |||
function URIutil.coreISSN( attempt ) | |||
-- Fetch significant ISSN | |||
-- Precondition: | |||
-- attempt -- string with presumable ISSN | |||
-- Postcondition: | |||
-- Returns string with 7 digits, without check digit nor GTIN | |||
-- unmodified input if wrong | |||
local r; | |||
local issn = ISSNfactory( attempt ); | |||
if type( issn ) == "table" then | |||
if issn.type == 8 then | |||
r = format( issn, 1, 7 ); | |||
elseif issn.type == 13 then | |||
r = format( issn, 4, 7 ); | |||
end | |||
else | |||
r = mw.ustring.upper( mw.text.trim( attempt ) ); | |||
end | |||
return r; | |||
end -- URIutil.coreISSN() | |||
function URIutil.formatISBN( attempt, assigned ) | |||
-- Format ISBN, if no hyphens present | |||
-- Precondition: | |||
-- attempt -- string with presumable ISBN | |||
-- assigned -- table or false; as of ISBNfactory() | |||
-- Postcondition: | |||
-- Returns string with some hyphens, if not yet | |||
-- unmodified input if already hyphens or wrong | |||
local r; | |||
local isbn; | |||
if type( assigned ) == "table" then | |||
isbn = assigned; | |||
else | |||
isbn = ISBNfactory( attempt ); | |||
end | |||
if type( isbn ) == "table" then | |||
r = ISBNformat( attempt, isbn ); | |||
else | |||
r = mw.ustring.upper( mw.text.trim( attempt ) ); | |||
end | |||
return r; | |||
end -- URIutil.formatISBN() | |||
function URIutil.formatISSN( attempt, achieve ) | |||
-- Format ISSN | |||
-- Precondition: | |||
-- attempt -- string with presumable ISSN | |||
-- achieve -- false or 8 or 13; requested presentation | |||
-- Postcondition: | |||
-- Returns string with some hyphens, if not yet | |||
-- unmodified input if already hyphens or wrong | |||
local r = false; | |||
local issn = ISSNfactory( attempt ); | |||
if type( issn ) == "table" then | |||
if ISSNfaith( issn ) then | |||
local k, m; | |||
if type( achieve ) == "string" then | |||
m = tonumber( achieve ); | |||
else | |||
m = achieve; | |||
end | |||
if m == 8 or m == 13 then | |||
k = m; | |||
else | |||
k = issn.type; | |||
end | |||
r = ISSNformat( issn, k ); | |||
end | |||
end | |||
if not r then | |||
r = mw.ustring.upper( mw.text.trim( attempt ) ); | |||
end | |||
return r; | |||
end -- URIutil.formatISSN() | |||
function URIutil.formatLCCN( attempt, achieve ) | |||
-- Standard or hyphen formatting of LCCN | |||
-- Precondition: | |||
-- attempt -- string with presumable LCCN | |||
-- achieve -- additional formatting desires, like "-" | |||
-- Postcondition: | |||
-- Returns string with letters, digits and hyphens | |||
-- unmodified input if wrong | |||
local r = LCCNfactory( attempt ); | |||
if r then | |||
r = LCCNformat( r, achieve ); | |||
end | |||
return r; | |||
end -- URIutil.formatLCCN() | |||
function URIutil.isDNBvalid( attempt, also ) | |||
-- Is this DNB (also GND, ZDB) formally correct (check digit)? | |||
-- Precondition: | |||
-- attempt -- string with any presumable DNB code | |||
-- also -- string or nil; optional requirement DMA GND SWD | |||
-- "ZDB" -- permit hyphen, but use >2011 rule | |||
-- DMA starting with 3 and no hyphen | |||
-- GND not DNB2011 | |||
-- SWD DNB2011 starting with 4 or 7 and no X check | |||
-- Postcondition: | |||
-- Returns number of digits or 2011, if valid | |||
-- false if not correct, bad data or check digit wrong | |||
local s = mw.text.trim( attempt ); | |||
local j = s:find( "/", 5, true ); | |||
local r = false; | |||
local dnb; | |||
if j then | |||
s = attempt:sub( 1, j - 1 ); | |||
end | |||
j = s:find( "-", 2, true ); | |||
if j then | |||
if j > 3 and j <= 8 then | |||
if s:match( "^[0-9]+-[0-9xX]$" ) then | |||
dnb = factory( s, true ); | |||
end | |||
end | |||
elseif #s > 6 then | |||
if s:match( "^[0-9]+[0-9xX]$" ) then | |||
dnb = factory( s, #s ); | |||
end | |||
end | |||
if type( dnb ) == "table" then | |||
if j then | |||
if DNBfaith( dnb, true ) then | |||
r = 2011; | |||
elseif type( also ) == "string" then | |||
s = mw.text.trim( also ); | |||
if s == "ZDB" then | |||
if DNBfaith( dnb, false ) then | |||
r = dnb.type; | |||
end | |||
end | |||
end | |||
else | |||
if DNBfaith( dnb, false ) then | |||
r = dnb.type; | |||
elseif type( also ) == "string" then | |||
s = mw.text.trim( also ); | |||
if s == "ZDB" then | |||
if DNBfaith( dnb, true ) then | |||
r = dnb.type; | |||
end | |||
end | |||
end | |||
end | |||
end | |||
return r; | |||
end -- URIutil.isDNBvalid() | |||
function URIutil.isDOI( attempt ) | |||
-- Is this a syntactically correct DOI? | |||
-- Precondition: | |||
-- attempt -- string with presumable DOI code | |||
-- Postcondition: | |||
-- Returns number of organization, if valid | |||
-- false if not correct, bad character or syntax | |||
local r = false; | |||
local k, s = attempt:match( "^%s*10%.([1-9][0-9]+)/(.+)%s*$" ); | |||
if k then | |||
k = tonumber( k ); | |||
if k >= 1000 and k < 100000000 then | |||
local pc = "^[0-9A-Za-z%(%[<%./]" | |||
.. "[%-0-9/A-Z%.a-z%(%)_%[%];,:<>%+]*" | |||
.. "[0-9A-Za-z%)%]>%+#]$" | |||
s = mw.uri.decode( mw.text.decode( s ), "PATH" ); | |||
if s:match( pc ) then | |||
r = k; | |||
end | |||
end | |||
end | |||
return r; | |||
end -- URIutil.isDOI() | |||
function URIutil.isEscValid( attempt ) | |||
-- Are bad percent escapings in attempt? | |||
-- Precondition: | |||
-- attempt -- string with possible percent escapings | |||
-- Postcondition: | |||
-- Returns string with violating sequence | |||
-- false if correct | |||
local i = 0; | |||
local r = false; | |||
local h, s; | |||
while i do | |||
i = attempt:find( "%", i, true ); | |||
if i then | |||
s = attempt:sub( i + 1, i + 2 ); | |||
h = s:match( "%x%x" ); | |||
if h then | |||
if h == "00" then | |||
r = "%00"; | |||
break; -- while i | |||
end | |||
i = i + 2; | |||
else | |||
r = "%" .. s; | |||
break; -- while i | |||
end | |||
end | |||
end -- while i | |||
return r; | |||
end -- URIutil.isEscValid() | |||
function URIutil.isGTINvalid( attempt ) | |||
-- Is this GTIN (EAN) formally correct (check digit)? | |||
-- Precondition: | |||
-- attempt -- string with presumable GTIN | |||
-- Postcondition: | |||
-- Returns GTIN length | |||
-- false if not correct, bad data or check digit wrong | |||
local r; | |||
local gtin = factory( attempt, false ); | |||
if type( gtin ) == "table" then | |||
if gtin.type == 13 then | |||
if GTINfaith( gtin ) then | |||
r = gtin.type; | |||
end | |||
else | |||
r = false; | |||
end | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- URIutil.isGTINvalid() | |||
function URIutil.isHandle( attempt ) | |||
-- Is this a meaningful handle for handle.net? | |||
-- Precondition: | |||
-- attempt -- string with presumable handle code | |||
-- Postcondition: | |||
-- Returns number of primary authority, if valid | |||
-- false if not correct, bad character or syntax | |||
local r = attempt:match( "^%s*([^/%s]+)/%S+%s*$" ); | |||
if r then | |||
local k = r:find( ".", 1, true ); | |||
if k then | |||
if k == 1 or r:match( "%.$" ) then | |||
r = false; | |||
else | |||
r = r:sub( 1, k - 1 ); | |||
end | |||
end | |||
if r then | |||
if r:match( "^[1-9][0-9]+$" ) then | |||
r = tonumber( r ); | |||
else | |||
r = false; | |||
end | |||
end | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- URIutil.isHandle() | |||
function URIutil.isISBN( attempt ) | |||
-- Is this a syntactically correct ISBN? | |||
-- Precondition: | |||
-- attempt -- string with presumable ISBN | |||
-- Postcondition: | |||
-- Returns | |||
-- 1 -- 10 if 10 digits and hyphens; also X at end of ISBN-10 | |||
-- 13 if 13 digits and hyphens; beginning with bookland | |||
-- false if not an ISBN | |||
-- 2 -- internal table, if (1) | |||
-- number; no string or bad length or data | |||
-- 0 -- no string | |||
-- >0 -- unexpected char at position (trimmed) | |||
-- -1 -- bad digit count | |||
-- -2 -- bad bookland | |||
local r; | |||
local isbn = ISBNfactory( attempt ); | |||
if type( isbn ) == "table" then | |||
r = isbn.type; | |||
else | |||
r = false; | |||
end | |||
return r, isbn; | |||
end -- URIutil.isISBN() | |||
function URIutil.isISBNvalid( attempt ) | |||
-- Is this ISBN formally correct (check digit)? | |||
-- Precondition: | |||
-- attempt -- string with presumable ISBN | |||
-- Postcondition: | |||
-- Returns | |||
-- 1 -- 10 if 10 digits and hyphens; also X at end of ISBN-10 | |||
-- 13 if 13 digits and hyphens; beginning with bookland | |||
-- false if not correct, bad data or check digit wrong | |||
-- 2 -- internal table, if (1) | |||
-- number; no string or bad length or data | |||
-- 0 -- no string | |||
-- >0 -- unexpected char at position (trimmed) | |||
-- -1 -- bad digit count | |||
-- -2 -- bad bookland | |||
local r = false; | |||
local isbn = ISBNfactory( attempt ); | |||
if type( isbn ) == "table" then | |||
if ISBNfaith( isbn ) then | |||
r = isbn.type; | |||
end | |||
end | |||
return r, isbn; | |||
end -- URIutil.isISBNvalid() | |||
function URIutil.isISSNvalid( attempt ) | |||
-- Is this ISSN formally correct (check digit)? | |||
-- Precondition: | |||
-- attempt -- string with presumable ISSN | |||
-- Postcondition: | |||
-- Returns 8 if 8 digits and up to 1 hyphen; also X at end | |||
-- 13 if 13 digits and hyphens; beginning with 977 | |||
-- false if not correct, bad data or check digit wrong | |||
local r = false; | |||
local issn = ISSNfactory( attempt ); | |||
if type( issn ) == "table" then | |||
if ISSNfaith( issn ) then | |||
r = issn.type; | |||
end | |||
end | |||
return r; | |||
end -- URIutil.isISSNvalid() | |||
function URIutil.isLCCN( attempt, allow ) | |||
-- Is this a syntactically correct LCCN? | |||
-- Precondition: | |||
-- attempt -- string with presumable LCCN | |||
-- allow -- false or string: "/" | |||
-- Postcondition: | |||
-- Returns string with LCCN formatted aa9999-99999999 | |||
-- false if not correct, bad data | |||
local r = false; | |||
local lccn = LCCNfactory( attempt, allow ); | |||
if lccn then | |||
r = LCCNformat( lccn, "-" ); | |||
end | |||
return r; | |||
end -- URIutil.isLCCN() | |||
function URIutil.linkDNBopac( attempt, about, allow, abbr, alert ) | |||
-- Retrieve bracketed titled external DNB opac link | |||
-- Precondition: | |||
-- attempt -- string with presumable DNB ID | |||
-- about -- title, or false | |||
-- allow -- true: permit invalid ID | |||
-- abbr -- true: link DNB abbreviation | |||
-- alert -- string with title of maintenance category, or nil | |||
-- Postcondition: | |||
-- Returns link, or plain string if bad DNB | |||
local r = allow or URIutil.isDNBvalid( attempt ); | |||
local s = "DNB"; | |||
if abbr and not about then | |||
local cnf = fetch( "config" ); | |||
if cnf.supportDNB and cnf.supportDNB ~= fullPageName() then | |||
s = string.format( "[[%s|DNB]]", cnf.supportDNB ); | |||
end | |||
end | |||
if r then | |||
if about then | |||
r = about; | |||
else | |||
r = attempt; | |||
end | |||
r = string.format( "%s [%s%s%s%s%s %s]", | |||
s, | |||
"https://portal.dnb.de/opac.htm", | |||
"?referrer=Wikipedia", | |||
"&method=simpleSearch&cqlMode=true", | |||
"&query=idn%3D", | |||
attempt, | |||
r ); | |||
else | |||
r = string.format( "%s %s", s, attempt ); | |||
if about then | |||
r = string.format( "%s %s", r, about ); | |||
end | |||
if alert then | |||
r = r .. flop( alert ); | |||
end | |||
end | |||
return r; | |||
end -- URIutil.linkDNBopac() | |||
function URIutil.linkDOI( attempt, any1, any2, any3, alert ) | |||
-- Retrieve bracketed titled external link on DOI resolver | |||
-- Precondition: | |||
-- attempt -- string with presumable DOI | |||
-- any1 -- intentionally dummy parameter | |||
-- any2 -- intentionally dummy parameter | |||
-- any3 -- intentionally dummy parameter | |||
-- alert -- string with title of maintenance category, or nil | |||
-- Postcondition: | |||
-- Returns external link, or false | |||
local r = URIutil.isDOI( attempt ); | |||
if r then | |||
r = mw.text.decode( mw.text.trim( attempt ), "PATH" ); | |||
r = string.format( "[%s%s %s]", | |||
"//dx.doi.org/", | |||
mw.uri.encode( r ), | |||
mw.text.encode( r, "<>&%]" ) ); | |||
r = string.format( "<span class='uri-handle'>%s</span>", r ); | |||
else | |||
r = flop( alert ); | |||
end | |||
return r; | |||
end -- URIutil.linkDOI() | |||
function URIutil.linkHandle( attempt, any1, any2, any3, alert ) | |||
-- Retrieve bracketed titled external link on handle resolver | |||
-- Precondition: | |||
-- attempt -- string with presumable handle | |||
-- any1 -- intentionally dummy parameter | |||
-- any2 -- intentionally dummy parameter | |||
-- any3 -- intentionally dummy parameter | |||
-- alert -- string with title of maintenance category, or nil | |||
-- Postcondition: | |||
-- Returns external link, or false | |||
local r = URIutil.isHandle( attempt ); | |||
if r then | |||
r = mw.text.decode( mw.text.trim( attempt ), "PATH" ); | |||
r = string.format( "[%s%s %s]", | |||
"//hdl.handle.net/", | |||
mw.uri.encode( r ), | |||
mw.text.encode( r, "<>&%]" ) ); | |||
r = string.format( "<span class='uri-handle'>%s</span>", r ); | |||
else | |||
r = flop( alert ); | |||
end | |||
return r; | |||
end -- URIutil.linkHandle() | |||
function URIutil.linkISBN( attempt, allow, abbr, adhere, alert ) | |||
-- Retrieve bracketed titled wikilink on booksources page with "ISBN" | |||
-- Precondition: | |||
-- attempt -- string with presumable ISBN | |||
-- allow -- true: permit invalid check digit or digit count | |||
-- abbr -- true or string: link ISBN abbreviation | |||
-- adhere -- true: use else: use simple space | |||
-- alert -- string with title of maintenance category, or nil | |||
-- Postcondition: | |||
-- Returns link | |||
local lapsus; | |||
local source = mw.text.trim( attempt ); | |||
local r = string.format( "[[Special:Booksources/%s|", source ); | |||
local isbn = ISBNfactory( source ); | |||
if type( isbn ) == "table" then | |||
local lenient; | |||
if type( allow ) == "string" then | |||
lenient = ( allow ~= "0" ); | |||
else | |||
lenient = allow; | |||
end | |||
if lenient then | |||
lapsus = false; | |||
else | |||
lapsus = ( not ISBNfaith( isbn ) ); | |||
end | |||
r = r .. ISBNformat( attempt, isbn ); | |||
else | |||
lapsus = not allow; | |||
r = r .. source; | |||
end | |||
r = r .. "]]"; | |||
if lapsus then | |||
r = string.format( "<span class='invalid-ISBN'>%s</span>%s", | |||
r, fault( "(?!?!)" ) ); | |||
if alert then | |||
r = r .. flop( alert ); | |||
end | |||
end | |||
if adhere then | |||
r = " " .. r; | |||
else | |||
r = " " .. r; | |||
end | |||
if abbr then | |||
local cnf = fetch( "config" ); | |||
local s = cnf.supportISBN; | |||
if s then | |||
if type( s ) ~= "string" | |||
or s == "" then | |||
s = false; | |||
end | |||
else | |||
s = "International Standard Book Number"; | |||
end | |||
if s and s ~= fullPageName() then | |||
s = string.format( "[[%s|ISBN]]", s ); | |||
else | |||
s = "ISBN"; | |||
end | |||
r = string.format( "%s %s", s, r ); | |||
else | |||
r = "ISBN" .. r; | |||
end | |||
return r; | |||
end -- URIutil.linkISBN() | |||
function URIutil.linkISSN( attempt, allow, abbr, adhere, alert ) | |||
-- Retrieve bracketed titled external link on ISSN DB with "ISSN" | |||
-- Precondition: | |||
-- attempt -- string with presumable ISSN | |||
-- allow -- true: permit invalid check digit | |||
-- abbr -- true: link ISSN abbreviation | |||
-- adhere -- true: use else: use simple space; | |||
-- alert -- string with title of maintenance category, or nil | |||
-- Postcondition: | |||
-- Returns link | |||
local r = URIutil.targetISSN( attempt, allow, nil, nil, alert ); | |||
if adhere then | |||
r = " " .. r; | |||
else | |||
r = " " .. r; | |||
end | |||
if abbr then | |||
local cnf = fetch( "config" ); | |||
local s = cnf.supportISSN; | |||
if s then | |||
if type( s ) ~= "string" | |||
or s == "" then | |||
s = false; | |||
end | |||
else | |||
s = "International Standard Serial Number"; | |||
end | |||
if s and s ~= fullPageName() then | |||
s = string.format( "[[%s|ISSN]]", s ); | |||
else | |||
s = "ISSN"; | |||
end | |||
r = string.format( "%s%s", s, r ); | |||
else | |||
r = "ISSN" .. r; | |||
end | |||
return r; | |||
end -- URIutil.linkISSN() | |||
function URIutil.linkLCCN( attempt, achieve, any1, any2, alert ) | |||
-- Retrieve bracketed titled external LCCN permalink | |||
-- Precondition: | |||
-- attempt -- string with presumable LCCN | |||
-- achieve -- additional title formatting desires, like "-" | |||
-- any1 -- intentionally dummy parameter | |||
-- any2 -- intentionally dummy parameter | |||
-- alert -- string with title of maintenance category, or nil | |||
-- Postcondition: | |||
-- Returns link, or false if bad LCCN | |||
local r = LCCNforward( attempt, achieve ); | |||
if not r then | |||
r = flop( alert ); | |||
end | |||
return r; | |||
end -- URIutil.linkLCCN() | |||
function URIutil.linkURN( attempt, alter, any1, any2, alert ) | |||
-- Retrieve bracketed titled external URN link | |||
-- Precondition: | |||
-- attempt -- string, with presumable URN, starting with "urn:" | |||
-- alter -- alternative handler | |||
-- any1 -- intentionally dummy parameter | |||
-- any2 -- intentionally dummy parameter | |||
-- alert -- string, with title of maintenance category, or nil | |||
-- Postcondition: | |||
-- Returns | |||
-- 1. linked ID, or plain string if bad URN | |||
-- 2. true, if to be preceded by "urn:" | |||
local r2 = true; | |||
local r; | |||
if not URIutil.mayURI( attempt, true ) then | |||
local s = attempt:match( "^%s*[uU][rR][nN]:(%S+)%s*$" ); | |||
if s then | |||
local space, sign = s:match( "^(%w+):(.+)$" ); | |||
if space then | |||
local defs = fetch( "urn" ); | |||
if type( defs ) == "table" then | |||
local resolver = defs.resolver; | |||
space = space:lower(); | |||
resolver = resolver[ space ]; | |||
r2 = ( resolver ~= true ); | |||
if type( resolver ) == "table" then | |||
r, sign = URNresolve( resolver, sign, alter ); | |||
s = string.format( "%s:%s", space, sign ); | |||
if r then | |||
r = r:gsub( "%$1", "urn:" .. s ); | |||
r = string.format( "[%s %s]", r, s ); | |||
end | |||
elseif r2 then | |||
if type( defs.sns ) == "string" then | |||
s = string.format( ":%s:", space ); | |||
if not defs.sns:find( s, 1, true ) then | |||
s = false; | |||
end | |||
else | |||
s = false; | |||
end | |||
if s then | |||
r = string.format( "%s:%s", space, sign ); | |||
else | |||
r = string.format( "%s:%s", | |||
space, sign ); | |||
end | |||
else | |||
s = "link" .. space:upper(); | |||
r = URIutil[ s ]( sign, alter, nil, nil, alert ); | |||
end | |||
else | |||
r = fault( "Bad structure in Module:URIutil/urn" ); | |||
end | |||
end | |||
end | |||
end | |||
if not r then | |||
if alert then | |||
r = flop( alert ) or ""; | |||
if attempt then | |||
r = attempt .. r; | |||
end | |||
else | |||
r = mw.text.trim( attempt ); | |||
end | |||
end | |||
return r, r2; | |||
end -- URIutil.linkURN() | |||
function URIutil.mayDOI( attempt ) | |||
-- Is this a syntactically correct DOI, or empty? | |||
-- Precondition: | |||
-- attempt -- string with presumable DOI | |||
-- Postcondition: | |||
-- Returns number of organization | |||
-- 0 if empty | |||
-- false if not empty and not a DOI | |||
local r; | |||
if type( attempt ) == "string" then | |||
local s = mw.text.trim( attempt ); | |||
if #s >= 10 then | |||
r = URIutil.isDOI( attempt ); | |||
elseif #s == 0 then | |||
r = 0; | |||
else | |||
r = false; | |||
end | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- URIutil.mayDOI() | |||
function URIutil.mayHandle( attempt ) | |||
-- Is this a meaningful handle, or empty? | |||
-- Precondition: | |||
-- attempt -- string with presumable handle | |||
-- Postcondition: | |||
-- Returns number of organization | |||
-- 0 if empty | |||
-- false if not empty and not a DOI | |||
local r; | |||
if type( attempt ) == "string" then | |||
local s = mw.text.trim( attempt ); | |||
if #s > 5 then | |||
r = URIutil.isHandle( attempt ); | |||
elseif #s == 0 then | |||
r = 0; | |||
else | |||
r = false; | |||
end | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- URIutil.mayHandle() | |||
function URIutil.mayISBN( attempt ) | |||
-- Is this a syntactically correct ISBN, or empty? | |||
-- Precondition: | |||
-- attempt -- string with presumable ISBN | |||
-- Postcondition: | |||
-- Returns 10 if 10 digits and hyphens; also X at end of ISBN-10 | |||
-- 13 if 13 digits and hyphens; beginning with bookland | |||
-- 0 if empty | |||
-- false if not empty and not an ISBN | |||
local r; | |||
if type( attempt ) == "string" then | |||
local s = mw.text.trim( attempt ); | |||
if #s >= 10 then | |||
r = URIutil.isISBN( attempt ); | |||
elseif #s == 0 then | |||
r = 0; | |||
else | |||
r = false; | |||
end | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- URIutil.mayISBN() | |||
function URIutil.mayISSN( attempt ) | |||
-- Is this a correct ISSN, or empty? | |||
-- Precondition: | |||
-- attempt -- string with presumable ISSN | |||
-- Postcondition: | |||
-- Returns 8 if 8 digits and hyphens; also X at end | |||
-- 13 if 13 digits and hyphens; beginning with issnland | |||
-- 0 if empty | |||
-- false if not empty and not an ISSN | |||
local r; | |||
if type( attempt ) == "string" then | |||
local s = mw.text.trim( attempt ); | |||
if #s >= 8 then | |||
r = URIutil.isISSNvalid( attempt ); | |||
elseif #s == 0 then | |||
r = 0; | |||
else | |||
r = false; | |||
end | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- URIutil.mayISSN() | |||
function URIutil.mayLCCN( attempt ) | |||
-- Is this a syntactically correct LCCN? | |||
-- Precondition: | |||
-- attempt -- string with presumable LCCN | |||
-- Postcondition: | |||
-- Returns string with LCCN formatted aa9999-99999999 | |||
-- 0 if empty | |||
-- false if not recognized | |||
if type( attempt ) == "string" then | |||
local s = mw.text.trim( attempt ); | |||
if s == "" then | |||
r = 0; | |||
else | |||
r = URIutil.isLCCN( s ); | |||
end | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- URIutil.mayLCCN() | |||
function URIutil.mayURI( attempt, ascii ) | |||
-- Is this a syntactically correct URI, or empty? | |||
-- Precondition: | |||
-- attempt -- string with presumable URI | |||
-- ascii -- limit to ASCII (no IRI) | |||
-- Postcondition: | |||
-- Returns false if no problem | |||
-- string with violation | |||
local r = URIutil.isEscValid( attempt ); | |||
if not r then | |||
local s = mw.text.trim( attempt ); | |||
r = s:match( "%s(.+)$" ); | |||
if not r then | |||
r = s:match( "#(.*)$" ); | |||
if r then | |||
r = "#" .. r; | |||
elseif ascii then | |||
local p = string.format( "[%s].+$", | |||
mw.ustring.char( 128,45,255 ) ); | |||
r = mw.ustring.match( s, p ); | |||
end | |||
end | |||
end | |||
return r; | |||
end -- URIutil.mayURI() | |||
function URIutil.mayURN( attempt ) | |||
-- Is this a syntactically correct URN, or empty? | |||
-- Precondition: | |||
-- attempt -- string with presumable URN, starting with "urn:" | |||
-- Postcondition: | |||
-- Returns false if no problem | |||
-- string with violation | |||
local r = URIutil.mayURI( attempt, true ); | |||
if not r then | |||
local s = attempt:match( "^%s*[uU][rR][nN]:(.+)$" ); | |||
if s then | |||
local space, id = s:match( "^(%w+):(.+)$" ); | |||
if space then | |||
r = URNnamespace( space:lower(), id ); | |||
else | |||
r = s; | |||
end | |||
elseif mw.text.trim( attempt ) == "" then | |||
r = false; | |||
else | |||
r = "urn:"; | |||
end | |||
end | |||
return r; | |||
end -- URIutil.mayURN() | |||
function URIutil.plainISBN( attempt ) | |||
-- Format ISBN as digits (and 'X') only string | |||
-- Precondition: | |||
-- attempt -- string with presumable ISBN | |||
-- Postcondition: | |||
-- Returns string with 10 or 13 chars | |||
-- false if not empty and not an ISBN | |||
local r; | |||
local isbn = ISBNfactory( attempt ); | |||
if type( isbn ) == "table" then | |||
r = ISBNflat( isbn ); | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- URIutil.plainISBN() | |||
function URIutil.targetISSN( attempt, allow, any1, any2, alert ) | |||
-- Retrieve bracketed titled external link on ISSN DB without "ISSN" | |||
-- Precondition: | |||
-- attempt -- string with presumable ISSN | |||
-- allow -- true: permit invalid check digit | |||
-- any1 -- intentionally dummy parameter | |||
-- any2 -- intentionally dummy parameter | |||
-- alert -- string with title of maintenance category, or nil | |||
-- Postcondition: | |||
-- Returns link | |||
local cnf = fetch( "config" ); | |||
local issn = ISSNfactory( attempt ); | |||
local lapsus, r; | |||
if type( issn ) == "table" then | |||
local lenient; | |||
if type( allow ) == "string" then | |||
lenient = ( allow ~= "0" ); | |||
else | |||
lenient = allow; | |||
end | |||
if lenient then | |||
lapsus = false; | |||
else | |||
lapsus = ( not ISSNfaith( issn ) ); | |||
end | |||
r = ISSNformat( issn, issn.type ); | |||
if type( cnf.issn ) == "string" then | |||
r = string.format( "[%s %s]", | |||
cnf.issn:gsub( "%$1", r ), | |||
r ); | |||
end | |||
else | |||
lapsus = true; | |||
r = attempt; | |||
end | |||
if lapsus then | |||
r = string.format( "<span class='invalid-ISSN'>%s</span>%s", | |||
r, fault( "(?!?!)" ) ); | |||
if alert then | |||
r = r .. flop( alert ); | |||
end | |||
end | |||
return r; | |||
end -- URIutil.targetISSN() | |||
function URIutil.uriDOI( attempt, anything, abbr ) | |||
-- Retrieve linked URI on DOI resolver | |||
-- Precondition: | |||
-- attempt -- string with presumable DOI | |||
-- anything -- intentionally dummy parameter | |||
-- abbr -- true or string: link doi: abbreviation | |||
local r = URIutil.linkDOI( attempt ); | |||
if r then | |||
if abbr then | |||
local s; | |||
if type( abbr ) == "string" then | |||
s = abbr; | |||
else | |||
s = "Digital Object Identifier"; | |||
end | |||
r = string.format( "[[%s|doi]]:%s", s, r ); | |||
else | |||
r = "doi:" .. r; | |||
end | |||
end | |||
return r; | |||
end -- URIutil.uriDOI() | |||
function URIutil.uriHandle( attempt, anything, abbr ) | |||
-- Retrieve linked URI on handle resolver | |||
-- Precondition: | |||
-- attempt -- string with presumable handle | |||
-- anything -- intentionally dummy parameter | |||
-- abbr -- true or string: link hdl: abbreviation | |||
local r = URIutil.linkHandle( attempt ); | |||
if r then | |||
local s; | |||
if type( abbr ) == "string" then | |||
s = abbr; | |||
end | |||
if s then | |||
r = string.format( "[[%s|hdl]]:%s", s, r ); | |||
else | |||
r = "hdl:" .. r; | |||
end | |||
end | |||
return r; | |||
end -- URIutil.uriHandle() | |||
function URIutil.uriURN( attempt, anything, alter, alert ) | |||
-- Retrieve linked URI on URN resolver | |||
-- Precondition: | |||
-- attempt -- string with presumable URN, starting with "urn:" | |||
-- anything -- intentionally dummy parameter | |||
-- alter -- string with alternative handler, or nil | |||
-- alert -- string with title of maintenance category, or nil | |||
-- Postcondition: | |||
-- Returns link, or plain string if bad URN | |||
local r, l = URIutil.linkURN( attempt, alter, false, false, alert ); | |||
if l then | |||
local s = fetch( "config" ).supportURN; | |||
if s then | |||
if type( s ) ~= "string" | |||
or s == "" then | |||
s = false; | |||
end | |||
else | |||
s = "Uniform Resource Name"; | |||
end | |||
if s then | |||
r = string.format( "[[%s|urn]]:%s", s, r ); | |||
else | |||
r = "urn:" .. r; | |||
end | |||
end | |||
return r; | |||
end -- URIutil.uriURN() | |||
URIutil.failsafe = function ( assert ) | |||
local r; | |||
if not assert or assert <= URIutil.serial then | |||
r = URIutil.serial; | |||
else | |||
r = false; | |||
end | |||
return r; | |||
end -- URIutil.failsafe() | |||
local Template = function ( frame, action ) | |||
-- Retrieve library result for template access | |||
-- Precondition: | |||
-- frame -- object | |||
-- action -- string; function name | |||
-- Postcondition: | |||
-- Returns appropriate string, or error message (development) | |||
local lucky, r = pcall( URIutil[ action ], | |||
frame.args[ 1 ] or "", | |||
frame.args[ 2 ], | |||
faculty( frame.args.link, true ), | |||
faculty( frame.args.nbsp, true ), | |||
frame.args.cat ); | |||
if lucky then | |||
if r then | |||
r = tostring( r ); | |||
else | |||
r = ""; | |||
end | |||
else | |||
r = fault( r ); | |||
end | |||
return r; | |||
end -- Template() | |||
-- Provide template access and expose URIutil table to require() | |||
local p = {}; | |||
function p.coreISSN( frame ) | |||
return Template( frame, "coreISSN" ); | |||
end | |||
function p.formatISBN( frame ) | |||
return Template( frame, "formatISBN" ); | |||
end | |||
function p.formatISSN( frame ) | |||
return Template( frame, "formatISSN" ); | |||
end | |||
function p.formatLCCN( frame ) | |||
return Template( frame, "formatLCCN" ); | |||
end | |||
function p.isDNBvalid( frame ) | |||
return Template( frame, "isDNBvalid" ); | |||
end | |||
function p.isDOI( frame ) | |||
return Template( frame, "isDOI" ); | |||
end | |||
function p.isEscValid( frame ) | |||
return Template( frame, "isEscValid" ); | |||
end | |||
function p.isGTINvalid( frame ) | |||
return Template( frame, "isGTINvalid" ); | |||
end | |||
function p.isHandle( frame ) | |||
return Template( frame, "isHandle" ); | |||
end | |||
function p.isISBN( frame ) | |||
return Template( frame, "isISBN" ); | |||
end | |||
function p.isISBNvalid( frame ) | |||
return Template( frame, "isISBNvalid" ); | |||
end | |||
function p.isISSNvalid( frame ) | |||
return Template( frame, "isISSNvalid" ); | |||
end | |||
function p.isLCCN( frame ) | |||
return Template( frame, "isLCCN" ); | |||
end | |||
function p.linkDNBopac( frame ) | |||
return Template( frame, "linkDNBopac" ); | |||
end | |||
function p.linkDOI( frame ) | |||
return Template( frame, "linkDOI" ); | |||
end | |||
function p.linkDOI( frame ) | |||
return Template( frame, "linkDOI" ); | |||
end | |||
function p.linkHandle( frame ) | |||
return Template( frame, "linkHandle" ); | |||
end | |||
function p.linkISBN( frame ) | |||
return Template( frame, "linkISBN" ); | |||
end | |||
function p.linkISSN( frame ) | |||
return Template( frame, "linkISSN" ); | |||
end | |||
function p.linkLCCN( frame ) | |||
return Template( frame, "linkLCCN" ); | |||
end | |||
function p.linkURN( frame ) | |||
return Template( frame, "linkURN" ); | |||
end | |||
function p.mayDOI( frame ) | |||
return Template( frame, "mayDOI" ); | |||
end | |||
function p.mayHandle( frame ) | |||
return Template( frame, "mayHandle" ); | |||
end | |||
function p.mayISBN( frame ) | |||
return Template( frame, "mayISBN" ); | |||
end | |||
function p.mayISSN( frame ) | |||
return Template( frame, "mayISSN" ); | |||
end | |||
function p.mayLCCN( frame ) | |||
return Template( frame, "mayLCCN" ); | |||
end | |||
function p.mayURI( frame ) | |||
return Template( frame, "mayURI" ); | |||
end | |||
function p.mayURN( frame ) | |||
return Template( frame, "mayURN" ); | |||
end | |||
function p.plainISBN( frame ) | |||
return Template( frame, "plainISBN" ); | |||
end | |||
function p.targetISSN( frame ) | |||
return Template( frame, "targetISSN" ); | |||
end | |||
function p.uriDOI( frame ) | |||
return Template( frame, "uriDOI" ); | |||
end | |||
function p.uriHandle( frame ) | |||
return Template( frame, "uriHandle" ); | |||
end | |||
function p.uriURN( frame ) | |||
return Template( frame, "uriURN" ); | |||
end | |||
p.failsafe = function ( frame ) | |||
local s = type( frame ); | |||
local since; | |||
if s == "table" then | |||
since = frame.args[ 1 ]; | |||
elseif s == "string" then | |||
since = frame; | |||
end | |||
if since then | |||
since = mw.text.trim( since ); | |||
if since == "" then | |||
since = false; | |||
end | |||
end | |||
return URIutil.failsafe( since ) or ""; | |||
end -- p.failsafe() | |||
function p.URIutil( arg ) | |||
local r; | |||
if arg then | |||
r = ""; | |||
else | |||
r = URIutil; | |||
end | |||
return r; | |||
end | |||
return p; |
Version vom 13. November 2017, 15:28 Uhr
Modul:LuaWiki:168: No transclude page 'Wikipedia:Lua/Modul-Navigationsfehler'
local URIutil = { suite = "URIutil", serial = "2017-10-04" }; --[=[ Utilities for URI etc. * coreISSN() * formatISBN() * formatISSN() * formatLCCN() * isDNBvalid() * isDOI() * isEscValid() * isGTINvalid() * isHandle() * isISBN() * isISBNvalid() * isISSNvalid() * isLCCN() * linkDNBopac() * linkDOI() * linkHandle() * linkISBN() * linkISSN() * linkLCCN() * linkURN() * mayDOI() * mayHandle() * mayISBN() * mayISSN() * mayLCCN() * mayURI() * mayURN() * plainISBN() * targetISSN() * uriDOI() * uriHandle() * uriURN() * failsafe() * URIutil() loadData: URIutil/config URIutil/isbn URIutil/urn ]=] local CurrentPageName local factory = function ( attempt, allowX ) -- Retrieve plain digits of attempt -- Precondition: -- attempt -- string; with digits (+xX) and hyphens, not trimmed -- allowX -- number; of (last) position for permitted xX -- boolean; xX at last position permitted -- Postcondition: -- Returns table; success -- [1]...[8]/[10]...[13] -- digits 0...9 -- 10 at last position -- .hyphens -- number of hyphens -- .type -- number of digits -- number; no string or bad length or data -- 0 -- no string -- >0 -- unexpected char at position (trimmed) local r; if type( attempt ) == "string" then local c, i; local j = 0; local k = 1; local s = mw.text.trim( attempt ); local n = mw.ustring.len( s ); r = { hyphens = 0 }; for i = 1, n do c = mw.ustring.codepoint( s, i, i + 1 ); if c >= 48 and c <= 57 then j = j + 1; r[ j ] = c - 48; k = false; elseif c == 45 then -- hyphen if i > 1 and i < n then r.hyphens = r.hyphens + 1; k = i; else r = j; break; end elseif c == 88 or c == 120 then -- X x j = j + 1; if allowX and i == n then if allowX == true or allowX == j then r[ j ] = 10; else r = j; end else r = j; end break; else r = j; break; end end -- for i if type( r ) == "table" then r.type = j; end else r = 0; end return r; end -- factory() local faculty = function ( ask, auto ) -- Evaluate possible string as boolean signal, if brief -- Precondition: -- ask -- trimmed string or nil or other -- auto -- fallback value if nil -- Postcondition: -- Returns appropriate value, or ask local r; if type( ask ) == "string" then if ask == "1" or ask == "" then r = true; elseif ask == "0" or ask == "-" then r = false; else r = ask; end elseif ask == nil then r = auto; else r = ask; end return r; end -- faculty() local fair = function ( assert ) -- Compute check digit (11 minus modulo 11) for descending factor -- Precondition: -- assert -- table; as of factory() -- .type -- number of digits including check digit -- Postcondition: -- Returns checksum local i; local n = assert.type; local k = n; local r = 0; for i = 1, n - 1 do r = r + k * assert[ i ]; k = k - 1; end -- for i return ( 11 - r % 11 ); end -- fair() local function fault( alert ) -- Format error message by class=error -- Parameter: -- alert -- string, error message -- Returns: -- string, HTML span return string.format( "<span class=\"error\">%s</span>", alert ); end -- fault() local fetch = function ( acquire ) -- Load data submodule -- Precondition: -- acquire -- string, one of -- "config" -- "isbn" -- "urn" -- Postcondition: -- Returns any table local r; if URIutil.data then r = URIutil.data[ acquire ]; else URIutil.data = { }; end if not r then local lucky; lucky, r = pcall( mw.loadData, "Module:URIutil/" .. acquire ); if type( r ) ~= "table" then r = { }; end URIutil.data[ acquire ] = r; end return r; end -- fetch() local flop = function ( alert ) -- Create link to (maintenance) category -- Precondition: -- alert -- trimmed string with title, not empty, or nil -- Postcondition: -- Returns link, or false local r; if type( alert ) == "string" and alert ~= "" then r = string.format( "[[Category:%s]]", alert ); end return r; end -- flop() local format = function ( assigned, ahead, amount ) -- Convert part of digit sequence into string -- Precondition: -- assigned -- table; as of factory() -- ahead -- index of first digit -- amount -- number of digits to append -- Postcondition: -- Returns string with digits and hyphens local i, k; local r = ""; for i = ahead, ahead + amount - 1 do k = assigned[ i ]; if k == 10 then r = r .. "X"; else r = r .. tostring( k ); end end -- for i return r; end -- format() local fullPageName = function () -- Retrieve current page name -- Postcondition: -- Returns string: current page name if not CurrentPageName then CurrentPageName = mw.title.getCurrentTitle().fullText; end return CurrentPageName; end -- fullPageName() local DNBfaith = function ( assert, ancestor ) -- Compute DNB (also GND, ZDB) check digit and verify -- Precondition: -- assert -- table; as of factory() -- .type -- until 11 including check digit -- ancestor -- true: 2011 mode -- Postcondition: -- Returns true: check digit matches -- 2013-09-01 local k = fair( assert ) % 11; if ancestor then k = 11 - k; end return ( k == assert[ assert.type ] ); end -- DNBfaith() local GTINfair = function ( assert ) -- Compute GTIN check digit -- Precondition: -- assert -- table; ~ 13 digits -- .type -- 13 ... -- Postcondition: -- Returns number 0...9 local i, k; local lead = true; local r = 0; for i = 1, assert.type - 1 do k = assert[ i ]; r = r + k; if lead then -- odd lead = false; else -- even r = r + k + k; lead = true; end end -- for i r = (10 - r % 10) % 10; return r; end -- GTINfair() local GTINfaith = function ( assert ) -- Compute GTIN check digit and verify -- Precondition: -- assert -- table; ~ 13 digits -- .type -- 13 ... -- Postcondition: -- Returns true: check digit matches return ( GTINfair( assert ) == assert[ assert.type ] ); end -- GTINfaith() local ISBNfactory = function ( attempt ) -- Retrieve plain digits of ISBN attempt -- Precondition: -- attempt -- string with digits (+xX) and hyphens, not trimmed -- Postcondition: -- Returns table; success -- [1]...[13] -- digits 0...9 -- 10 at ISBN-10 last position -- .type -- 10 or 13 -- .hyphens -- 0... number of hyphens -- number; no string or bad length or data -- 0 -- no string -- >0 -- unexpected char at position (trimmed) -- -1 -- bad digit count -- -2 -- bad bookland local r; if type( attempt ) == "string" then local s; r = factory( attempt, 10 ); s = type( r ); if s == "number" and r ~= 10 and r > 6 and r < 13 then r = factory( attempt, r ); s = type( r ); end if s == "table" then if r.type == 13 then if r[1] ~= 9 or r[2] ~= 7 or r[3] < 8 then r = -2; end elseif r.type ~= 10 then r = -1; end end else r = 0; end return r; end -- ISBNfactory() local ISBNfaith = function ( assert ) -- Compute ISBN check digit and verify -- Precondition: -- assert -- table; as of ISBNfactory() -- .type -- 10 or 13 -- Postcondition: -- Returns true: check digit matches local r; if assert.type == 10 then local i; local k = 0; for i = 1, 9 do k = k + i * assert[ i ]; end -- for i k = k % 11; r = ( k == assert[ 10 ] ); elseif assert.type == 13 then r = GTINfaith( assert ); else r = false; end return r; end -- ISBNfaith() local ISBNflat = function ( assigned ) -- Plain digits of attempt ISBN -- Precondition: -- assigned -- table; as of ISBNfactory() -- Postcondition: -- Returns string with digits; ISBN-10 with 'X' at last position local i; local r = ""; local n = assigned.type; if n == 10 then if assigned[ assigned.type ] == 10 then n = 9; end end for i = 1, n do r = r .. tostring( assigned[ i ] ); end -- for i if n == 9 then r = r .. "X"; end return r; end -- ISBNflat() local ISBNfold = function ( assigned, apply, allocate, already ) -- Retrieve number of digits for ISBN publisher/group -- Precondition: -- assigned -- table; as of ISBNfactory() -- apply -- number; of bookland (978 or 979) -- allocate -- number; of country -- already -- number; position in assigned to inspect -- Postcondition: -- Returns number of digits, at least 0 local r = 0; local def = fetch( "isbn" ); local bookland = def[ apply ]; if type( bookland ) == "table" then local country = bookland[ allocate ]; if type( country ) == "table" then local e, i, j, k, m, v; for i = 1, 4 do v = country[ i ]; if type( v ) == "table" then m = tonumber( format( assigned, already, i ) ); for k, e in pairs( v ) do if m >= e[ 1 ] and m <= e[ 2 ] then r = e[ 3 ]; break; -- for k end end -- for k end if r > 0 then break; -- for i end end -- for i end end return r; end -- ISBNfold() local ISBNformat = function ( attempt, assigned ) -- Hyphen formatting; at least try minimum -- Precondition: -- attempt -- string with presumable ISBN -- assigned -- table; as of ISBNfactory() -- .type -- 10 or 13 -- .hyphens -- 0...4 -- Postcondition: -- Returns string with digits and hyphens local r = false; local j, k, m, n; if assigned.type == 10 then m = 978; r = ""; j = 1; else m = 970 + assigned[ 3 ]; r = tostring( m ) .. "-"; j = 4; end if assigned[ j ] < 8 then k = 1; else k = 2; if assigned[ j ] == 9 and assigned[ j + 1 ] > 4 then k = 3; if assigned[ j + 1 ] > 8 then k = 4; if assigned[ j + 2 ] > 8 then k = 5; end end end end if k then n = format( assigned, j, k ); r = string.format( "%s%s-", r, n ); j = j + k; n = ISBNfold( assigned, m, tonumber( n ), j ); if n > 0 then r = string.format( "%s%s-", r, format( assigned, j, n ) ); j = j + n; end end r = r .. format( assigned, j, assigned.type - j ); if assigned[ assigned.type ] == 10 then r = r .. "-X"; else r = string.format( "%s-%s", r, tostring( assigned[ assigned.type ] ) ); end if not r then r = mw.ustring.upper( mw.text.trim( attempt ) ); end return r; end -- ISBNformat() local ISSNfactory = function ( attempt ) -- Retrieve plain digits of ISSN attempt -- Precondition: -- attempt -- string with digits (+xX) and hyphens, not trimmed -- Postcondition: -- Returns table; success -- [1]...[13] -- digits 0...9 -- 10 at ISSN-8 last position -- .type -- 8 or 13 -- .hyphens -- 0... number of hyphens -- number; no string or bad length or data -- 0 -- no string -- >0 -- unexpected char at position (trimmed) -- -1 -- bad digit count -- -2 -- bad issnland local r; if type( attempt ) == "string" then r = factory( attempt, 8 ); if type( r ) == "table" then if r.type == 13 then if r[1] ~= 9 or r[2] ~= 7 or r[3] ~= 7 then r = -2; end elseif r.type ~= 8 then r = -1; end end else r = 0; end return r; end -- ISSNfactory() local ISSNfaith = function ( assert ) -- Compute ISSN check digit and verify -- Precondition: -- assert -- table; as of ISSNfactory() -- .type -- 8 or 13 -- Postcondition: -- Returns true: check digit matches local r; if assert.type == 8 then local k = fair( assert ); if k == 11 then r = ( assert[ 8 ] == 0 ); else r = ( assert[ 8 ] == k ); end elseif assert.type == 13 then r = GTINfaith( assert ); else r = false; end return r; end -- ISSNfaith() local ISSNformat = function ( assigned, achieve ) -- Hyphen formatting of ISSN -- Precondition: -- assigned -- table; as of ISSNfactory(), and valid -- achieve -- 8 or 13 -- Postcondition: -- Returns string with digits and hyphens local r; if achieve == 8 then local x; if assigned.type == 8 then r = string.format( "%s-%s", format( assigned, 1, 4 ), format( assigned, 5, 3 ) ); x = assigned[ 8 ]; elseif assigned.type == 13 then r = string.format( "%s-%s", format( assigned, 4, 4 ), format( assigned, 8, 3 ) ); x = fair( assigned ); end if x == 10 then r = r .. "X"; else r = r .. tostring( x ); end elseif achieve == 13 then if assigned.type == 8 then r = string.format( "977-%s-00-%s", format( assigned, 1, 7 ), GTINfair( assigned ) ); elseif assigned.type == 13 then r = string.format( "977-%s%s-%s", format( assigned, 4, 7 ), format( assigned, 10, 2 ), tostring( assigned[ 13 ] ) ); end end return r; end -- ISSNformat() local LCCNfactory = function ( attempt, allow ) -- Retrieve segments of LCCN attempt (format since 2001) -- Precondition: -- attempt -- string with presumable LCCN -- allow -- false or string: "/" -- Postcondition: -- Returns table; success -- false if not correct, bad data -- 2014-12-28 local r = false; local pat = "^%s*(%a*)(/?)(%d%S+)%s*$"; local pre, sep, s = attempt:match( pat ); if pre and s then local year, serial; if pre == "" then pre = false; if sep ~= "" then s = false; end elseif #pre > 3 then s = false; else pre = pre:lower(); end if s then if allow ~= "/" or sep == "/" then if sep == "/" then year, serial = s:match( "^(%d+)/(%d.+)$" ); elseif s:find( "-", 2, true ) then year, serial = s:match( "^(%d+)%-(%d.+)$" ); else year = s:match( "^([%d]+)" ); if year then if #year <= 8 then year = s:sub( 1, 2 ); serial = s:sub( 3 ); elseif #year <= 10 then year = s:sub( 1, 4 ); serial = s:sub( 5 ); else year = false; serial = s; end elseif tonumber( s ) then serial = s; end end end if year then if #year == 4 then local n = tonumber( year ); if n <= 2000 then -- 2000 -> "00" serial = false; elseif n > tonumber( os.date( "%Y" ) ) then serial = false; end elseif #year ~= 2 then serial = false; end end if serial then r = { pre = pre, serial = serial }; if year then r.year = year; end if serial:find( "/", 2, true ) then local q; serial, q = serial:lower() :match( "^(%d+)/([a-z]+)$" ); if q == "dc" or q == "mads" or q == "marcxml" or q == "mods" then r.serial = serial; r.qualifier = q; end end if serial then serial = serial:match( "^0*([1-9]%d*)$" ); end if not serial then r = false; elseif #serial < 6 then r.serial = string.format( "%06d", tonumber( serial ) ); elseif #serial > 6 then r = false; end end end end return r; end -- LCCNfactory() local LCCNformat = function ( assigned, achieve ) -- Standard or hyphen or slash formatting of LCCN -- Precondition: -- assigned -- table; as of LCCNfactory(), and valid -- achieve -- additional formatting desires, like "-" or "/" -- Postcondition: -- Returns string with letters, digits and hyphens -- 2013-07-14 local r; if assigned.pre then r = assigned.pre; else r = ""; end if assigned.year then if achieve == "/" and r ~= "" then r = r .. "/"; end r = r .. assigned.year; if achieve then r = r .. achieve; end end if assigned.serial then r = r .. assigned.serial; end if assigned.qualifier then r = string.format( "%s/%s", r, assigned.qualifier ); end return r; end -- LCCNformat() local LCCNforward = function ( attempt, achieve ) -- Retrieve bracketed titled external LCCN permalink -- Precondition: -- attempt -- string with presumable LCCN -- achieve -- additional title formatting desires, like "-" -- Postcondition: -- Returns link, or plain attempt if bad LCCN -- 2015-08-10 local lccn = LCCNfactory( attempt ); local r; if lccn then r = LCCNformat( lccn, false ); if r then local s; if achieve then s = LCCNformat( lccn, achieve ); else s = r; end r = string.format( "[//lccn.loc.gov/%s %s]", r, s ); end else r = attempt; end return r; end -- LCCNforward() local URNnamespace = function ( area, acquire ) -- Are these parts of a correct URN? -- Precondition: -- area -- string with lowercase namespace -- acquire -- string with identification -- Postcondition: -- Returns false if no problem detected -- string with violation local s = fetch( "urn" ).sns; local r; if type( s ) == "string" then r = string.format( ":%s:", area ); if s:match( r ) then s = "[^%w%(%)%+,%-%.:=@;%$_!%*'].*$"; r = acquire:match( s ); else r = string.format( ":%s:", area ); end if not r then r = false; if area == "isbn" then if not URIutil.isISBNvalid( acquire ) then r = acquire; end elseif area == "issn" then if not URIutil.isISSNvalid( acquire ) then r = acquire; end end end end return r; end -- URNnamespace() local URNresolve = function ( assigned, ask, alter ) -- Resolve URN within space -- Precondition: -- assigned -- table with resolvers for this space -- ask -- string with ID within this space -- alter -- string with alternative resolver, or not -- Postcondition: -- Returns -- 1. URL of resolver, or nil -- 2. modified ask local resolver = assigned; local sign = ask; local subset = assigned[ ":" ]; local r; if subset then local s = sign:match( subset ); if s then s = s:lower(); sign = s .. sign:sub( #s + 1 ) if assigned[ s ] then resolver = assigned[ s ]; end end end if alter then r = resolver[ alter ]; end if not r then r = resolver[ "*" ]; end return r, sign; end -- URNresolve() function URIutil.coreISSN( attempt ) -- Fetch significant ISSN -- Precondition: -- attempt -- string with presumable ISSN -- Postcondition: -- Returns string with 7 digits, without check digit nor GTIN -- unmodified input if wrong local r; local issn = ISSNfactory( attempt ); if type( issn ) == "table" then if issn.type == 8 then r = format( issn, 1, 7 ); elseif issn.type == 13 then r = format( issn, 4, 7 ); end else r = mw.ustring.upper( mw.text.trim( attempt ) ); end return r; end -- URIutil.coreISSN() function URIutil.formatISBN( attempt, assigned ) -- Format ISBN, if no hyphens present -- Precondition: -- attempt -- string with presumable ISBN -- assigned -- table or false; as of ISBNfactory() -- Postcondition: -- Returns string with some hyphens, if not yet -- unmodified input if already hyphens or wrong local r; local isbn; if type( assigned ) == "table" then isbn = assigned; else isbn = ISBNfactory( attempt ); end if type( isbn ) == "table" then r = ISBNformat( attempt, isbn ); else r = mw.ustring.upper( mw.text.trim( attempt ) ); end return r; end -- URIutil.formatISBN() function URIutil.formatISSN( attempt, achieve ) -- Format ISSN -- Precondition: -- attempt -- string with presumable ISSN -- achieve -- false or 8 or 13; requested presentation -- Postcondition: -- Returns string with some hyphens, if not yet -- unmodified input if already hyphens or wrong local r = false; local issn = ISSNfactory( attempt ); if type( issn ) == "table" then if ISSNfaith( issn ) then local k, m; if type( achieve ) == "string" then m = tonumber( achieve ); else m = achieve; end if m == 8 or m == 13 then k = m; else k = issn.type; end r = ISSNformat( issn, k ); end end if not r then r = mw.ustring.upper( mw.text.trim( attempt ) ); end return r; end -- URIutil.formatISSN() function URIutil.formatLCCN( attempt, achieve ) -- Standard or hyphen formatting of LCCN -- Precondition: -- attempt -- string with presumable LCCN -- achieve -- additional formatting desires, like "-" -- Postcondition: -- Returns string with letters, digits and hyphens -- unmodified input if wrong local r = LCCNfactory( attempt ); if r then r = LCCNformat( r, achieve ); end return r; end -- URIutil.formatLCCN() function URIutil.isDNBvalid( attempt, also ) -- Is this DNB (also GND, ZDB) formally correct (check digit)? -- Precondition: -- attempt -- string with any presumable DNB code -- also -- string or nil; optional requirement DMA GND SWD -- "ZDB" -- permit hyphen, but use >2011 rule -- DMA starting with 3 and no hyphen -- GND not DNB2011 -- SWD DNB2011 starting with 4 or 7 and no X check -- Postcondition: -- Returns number of digits or 2011, if valid -- false if not correct, bad data or check digit wrong local s = mw.text.trim( attempt ); local j = s:find( "/", 5, true ); local r = false; local dnb; if j then s = attempt:sub( 1, j - 1 ); end j = s:find( "-", 2, true ); if j then if j > 3 and j <= 8 then if s:match( "^[0-9]+-[0-9xX]$" ) then dnb = factory( s, true ); end end elseif #s > 6 then if s:match( "^[0-9]+[0-9xX]$" ) then dnb = factory( s, #s ); end end if type( dnb ) == "table" then if j then if DNBfaith( dnb, true ) then r = 2011; elseif type( also ) == "string" then s = mw.text.trim( also ); if s == "ZDB" then if DNBfaith( dnb, false ) then r = dnb.type; end end end else if DNBfaith( dnb, false ) then r = dnb.type; elseif type( also ) == "string" then s = mw.text.trim( also ); if s == "ZDB" then if DNBfaith( dnb, true ) then r = dnb.type; end end end end end return r; end -- URIutil.isDNBvalid() function URIutil.isDOI( attempt ) -- Is this a syntactically correct DOI? -- Precondition: -- attempt -- string with presumable DOI code -- Postcondition: -- Returns number of organization, if valid -- false if not correct, bad character or syntax local r = false; local k, s = attempt:match( "^%s*10%.([1-9][0-9]+)/(.+)%s*$" ); if k then k = tonumber( k ); if k >= 1000 and k < 100000000 then local pc = "^[0-9A-Za-z%(%[<%./]" .. "[%-0-9/A-Z%.a-z%(%)_%[%];,:<>%+]*" .. "[0-9A-Za-z%)%]>%+#]$" s = mw.uri.decode( mw.text.decode( s ), "PATH" ); if s:match( pc ) then r = k; end end end return r; end -- URIutil.isDOI() function URIutil.isEscValid( attempt ) -- Are bad percent escapings in attempt? -- Precondition: -- attempt -- string with possible percent escapings -- Postcondition: -- Returns string with violating sequence -- false if correct local i = 0; local r = false; local h, s; while i do i = attempt:find( "%", i, true ); if i then s = attempt:sub( i + 1, i + 2 ); h = s:match( "%x%x" ); if h then if h == "00" then r = "%00"; break; -- while i end i = i + 2; else r = "%" .. s; break; -- while i end end end -- while i return r; end -- URIutil.isEscValid() function URIutil.isGTINvalid( attempt ) -- Is this GTIN (EAN) formally correct (check digit)? -- Precondition: -- attempt -- string with presumable GTIN -- Postcondition: -- Returns GTIN length -- false if not correct, bad data or check digit wrong local r; local gtin = factory( attempt, false ); if type( gtin ) == "table" then if gtin.type == 13 then if GTINfaith( gtin ) then r = gtin.type; end else r = false; end else r = false; end return r; end -- URIutil.isGTINvalid() function URIutil.isHandle( attempt ) -- Is this a meaningful handle for handle.net? -- Precondition: -- attempt -- string with presumable handle code -- Postcondition: -- Returns number of primary authority, if valid -- false if not correct, bad character or syntax local r = attempt:match( "^%s*([^/%s]+)/%S+%s*$" ); if r then local k = r:find( ".", 1, true ); if k then if k == 1 or r:match( "%.$" ) then r = false; else r = r:sub( 1, k - 1 ); end end if r then if r:match( "^[1-9][0-9]+$" ) then r = tonumber( r ); else r = false; end end else r = false; end return r; end -- URIutil.isHandle() function URIutil.isISBN( attempt ) -- Is this a syntactically correct ISBN? -- Precondition: -- attempt -- string with presumable ISBN -- Postcondition: -- Returns -- 1 -- 10 if 10 digits and hyphens; also X at end of ISBN-10 -- 13 if 13 digits and hyphens; beginning with bookland -- false if not an ISBN -- 2 -- internal table, if (1) -- number; no string or bad length or data -- 0 -- no string -- >0 -- unexpected char at position (trimmed) -- -1 -- bad digit count -- -2 -- bad bookland local r; local isbn = ISBNfactory( attempt ); if type( isbn ) == "table" then r = isbn.type; else r = false; end return r, isbn; end -- URIutil.isISBN() function URIutil.isISBNvalid( attempt ) -- Is this ISBN formally correct (check digit)? -- Precondition: -- attempt -- string with presumable ISBN -- Postcondition: -- Returns -- 1 -- 10 if 10 digits and hyphens; also X at end of ISBN-10 -- 13 if 13 digits and hyphens; beginning with bookland -- false if not correct, bad data or check digit wrong -- 2 -- internal table, if (1) -- number; no string or bad length or data -- 0 -- no string -- >0 -- unexpected char at position (trimmed) -- -1 -- bad digit count -- -2 -- bad bookland local r = false; local isbn = ISBNfactory( attempt ); if type( isbn ) == "table" then if ISBNfaith( isbn ) then r = isbn.type; end end return r, isbn; end -- URIutil.isISBNvalid() function URIutil.isISSNvalid( attempt ) -- Is this ISSN formally correct (check digit)? -- Precondition: -- attempt -- string with presumable ISSN -- Postcondition: -- Returns 8 if 8 digits and up to 1 hyphen; also X at end -- 13 if 13 digits and hyphens; beginning with 977 -- false if not correct, bad data or check digit wrong local r = false; local issn = ISSNfactory( attempt ); if type( issn ) == "table" then if ISSNfaith( issn ) then r = issn.type; end end return r; end -- URIutil.isISSNvalid() function URIutil.isLCCN( attempt, allow ) -- Is this a syntactically correct LCCN? -- Precondition: -- attempt -- string with presumable LCCN -- allow -- false or string: "/" -- Postcondition: -- Returns string with LCCN formatted aa9999-99999999 -- false if not correct, bad data local r = false; local lccn = LCCNfactory( attempt, allow ); if lccn then r = LCCNformat( lccn, "-" ); end return r; end -- URIutil.isLCCN() function URIutil.linkDNBopac( attempt, about, allow, abbr, alert ) -- Retrieve bracketed titled external DNB opac link -- Precondition: -- attempt -- string with presumable DNB ID -- about -- title, or false -- allow -- true: permit invalid ID -- abbr -- true: link DNB abbreviation -- alert -- string with title of maintenance category, or nil -- Postcondition: -- Returns link, or plain string if bad DNB local r = allow or URIutil.isDNBvalid( attempt ); local s = "DNB"; if abbr and not about then local cnf = fetch( "config" ); if cnf.supportDNB and cnf.supportDNB ~= fullPageName() then s = string.format( "[[%s|DNB]]", cnf.supportDNB ); end end if r then if about then r = about; else r = attempt; end r = string.format( "%s [%s%s%s%s%s %s]", s, "https://portal.dnb.de/opac.htm", "?referrer=Wikipedia", "&method=simpleSearch&cqlMode=true", "&query=idn%3D", attempt, r ); else r = string.format( "%s %s", s, attempt ); if about then r = string.format( "%s %s", r, about ); end if alert then r = r .. flop( alert ); end end return r; end -- URIutil.linkDNBopac() function URIutil.linkDOI( attempt, any1, any2, any3, alert ) -- Retrieve bracketed titled external link on DOI resolver -- Precondition: -- attempt -- string with presumable DOI -- any1 -- intentionally dummy parameter -- any2 -- intentionally dummy parameter -- any3 -- intentionally dummy parameter -- alert -- string with title of maintenance category, or nil -- Postcondition: -- Returns external link, or false local r = URIutil.isDOI( attempt ); if r then r = mw.text.decode( mw.text.trim( attempt ), "PATH" ); r = string.format( "[%s%s %s]", "//dx.doi.org/", mw.uri.encode( r ), mw.text.encode( r, "<>&%]" ) ); r = string.format( "<span class='uri-handle'>%s</span>", r ); else r = flop( alert ); end return r; end -- URIutil.linkDOI() function URIutil.linkHandle( attempt, any1, any2, any3, alert ) -- Retrieve bracketed titled external link on handle resolver -- Precondition: -- attempt -- string with presumable handle -- any1 -- intentionally dummy parameter -- any2 -- intentionally dummy parameter -- any3 -- intentionally dummy parameter -- alert -- string with title of maintenance category, or nil -- Postcondition: -- Returns external link, or false local r = URIutil.isHandle( attempt ); if r then r = mw.text.decode( mw.text.trim( attempt ), "PATH" ); r = string.format( "[%s%s %s]", "//hdl.handle.net/", mw.uri.encode( r ), mw.text.encode( r, "<>&%]" ) ); r = string.format( "<span class='uri-handle'>%s</span>", r ); else r = flop( alert ); end return r; end -- URIutil.linkHandle() function URIutil.linkISBN( attempt, allow, abbr, adhere, alert ) -- Retrieve bracketed titled wikilink on booksources page with "ISBN" -- Precondition: -- attempt -- string with presumable ISBN -- allow -- true: permit invalid check digit or digit count -- abbr -- true or string: link ISBN abbreviation -- adhere -- true: use else: use simple space -- alert -- string with title of maintenance category, or nil -- Postcondition: -- Returns link local lapsus; local source = mw.text.trim( attempt ); local r = string.format( "[[Special:Booksources/%s|", source ); local isbn = ISBNfactory( source ); if type( isbn ) == "table" then local lenient; if type( allow ) == "string" then lenient = ( allow ~= "0" ); else lenient = allow; end if lenient then lapsus = false; else lapsus = ( not ISBNfaith( isbn ) ); end r = r .. ISBNformat( attempt, isbn ); else lapsus = not allow; r = r .. source; end r = r .. "]]"; if lapsus then r = string.format( "<span class='invalid-ISBN'>%s</span>%s", r, fault( "(?!?!)" ) ); if alert then r = r .. flop( alert ); end end if adhere then r = " " .. r; else r = " " .. r; end if abbr then local cnf = fetch( "config" ); local s = cnf.supportISBN; if s then if type( s ) ~= "string" or s == "" then s = false; end else s = "International Standard Book Number"; end if s and s ~= fullPageName() then s = string.format( "[[%s|ISBN]]", s ); else s = "ISBN"; end r = string.format( "%s %s", s, r ); else r = "ISBN" .. r; end return r; end -- URIutil.linkISBN() function URIutil.linkISSN( attempt, allow, abbr, adhere, alert ) -- Retrieve bracketed titled external link on ISSN DB with "ISSN" -- Precondition: -- attempt -- string with presumable ISSN -- allow -- true: permit invalid check digit -- abbr -- true: link ISSN abbreviation -- adhere -- true: use else: use simple space; -- alert -- string with title of maintenance category, or nil -- Postcondition: -- Returns link local r = URIutil.targetISSN( attempt, allow, nil, nil, alert ); if adhere then r = " " .. r; else r = " " .. r; end if abbr then local cnf = fetch( "config" ); local s = cnf.supportISSN; if s then if type( s ) ~= "string" or s == "" then s = false; end else s = "International Standard Serial Number"; end if s and s ~= fullPageName() then s = string.format( "[[%s|ISSN]]", s ); else s = "ISSN"; end r = string.format( "%s%s", s, r ); else r = "ISSN" .. r; end return r; end -- URIutil.linkISSN() function URIutil.linkLCCN( attempt, achieve, any1, any2, alert ) -- Retrieve bracketed titled external LCCN permalink -- Precondition: -- attempt -- string with presumable LCCN -- achieve -- additional title formatting desires, like "-" -- any1 -- intentionally dummy parameter -- any2 -- intentionally dummy parameter -- alert -- string with title of maintenance category, or nil -- Postcondition: -- Returns link, or false if bad LCCN local r = LCCNforward( attempt, achieve ); if not r then r = flop( alert ); end return r; end -- URIutil.linkLCCN() function URIutil.linkURN( attempt, alter, any1, any2, alert ) -- Retrieve bracketed titled external URN link -- Precondition: -- attempt -- string, with presumable URN, starting with "urn:" -- alter -- alternative handler -- any1 -- intentionally dummy parameter -- any2 -- intentionally dummy parameter -- alert -- string, with title of maintenance category, or nil -- Postcondition: -- Returns -- 1. linked ID, or plain string if bad URN -- 2. true, if to be preceded by "urn:" local r2 = true; local r; if not URIutil.mayURI( attempt, true ) then local s = attempt:match( "^%s*[uU][rR][nN]:(%S+)%s*$" ); if s then local space, sign = s:match( "^(%w+):(.+)$" ); if space then local defs = fetch( "urn" ); if type( defs ) == "table" then local resolver = defs.resolver; space = space:lower(); resolver = resolver[ space ]; r2 = ( resolver ~= true ); if type( resolver ) == "table" then r, sign = URNresolve( resolver, sign, alter ); s = string.format( "%s:%s", space, sign ); if r then r = r:gsub( "%$1", "urn:" .. s ); r = string.format( "[%s %s]", r, s ); end elseif r2 then if type( defs.sns ) == "string" then s = string.format( ":%s:", space ); if not defs.sns:find( s, 1, true ) then s = false; end else s = false; end if s then r = string.format( "%s:%s", space, sign ); else r = string.format( "%s:%s", space, sign ); end else s = "link" .. space:upper(); r = URIutil[ s ]( sign, alter, nil, nil, alert ); end else r = fault( "Bad structure in Module:URIutil/urn" ); end end end end if not r then if alert then r = flop( alert ) or ""; if attempt then r = attempt .. r; end else r = mw.text.trim( attempt ); end end return r, r2; end -- URIutil.linkURN() function URIutil.mayDOI( attempt ) -- Is this a syntactically correct DOI, or empty? -- Precondition: -- attempt -- string with presumable DOI -- Postcondition: -- Returns number of organization -- 0 if empty -- false if not empty and not a DOI local r; if type( attempt ) == "string" then local s = mw.text.trim( attempt ); if #s >= 10 then r = URIutil.isDOI( attempt ); elseif #s == 0 then r = 0; else r = false; end else r = false; end return r; end -- URIutil.mayDOI() function URIutil.mayHandle( attempt ) -- Is this a meaningful handle, or empty? -- Precondition: -- attempt -- string with presumable handle -- Postcondition: -- Returns number of organization -- 0 if empty -- false if not empty and not a DOI local r; if type( attempt ) == "string" then local s = mw.text.trim( attempt ); if #s > 5 then r = URIutil.isHandle( attempt ); elseif #s == 0 then r = 0; else r = false; end else r = false; end return r; end -- URIutil.mayHandle() function URIutil.mayISBN( attempt ) -- Is this a syntactically correct ISBN, or empty? -- Precondition: -- attempt -- string with presumable ISBN -- Postcondition: -- Returns 10 if 10 digits and hyphens; also X at end of ISBN-10 -- 13 if 13 digits and hyphens; beginning with bookland -- 0 if empty -- false if not empty and not an ISBN local r; if type( attempt ) == "string" then local s = mw.text.trim( attempt ); if #s >= 10 then r = URIutil.isISBN( attempt ); elseif #s == 0 then r = 0; else r = false; end else r = false; end return r; end -- URIutil.mayISBN() function URIutil.mayISSN( attempt ) -- Is this a correct ISSN, or empty? -- Precondition: -- attempt -- string with presumable ISSN -- Postcondition: -- Returns 8 if 8 digits and hyphens; also X at end -- 13 if 13 digits and hyphens; beginning with issnland -- 0 if empty -- false if not empty and not an ISSN local r; if type( attempt ) == "string" then local s = mw.text.trim( attempt ); if #s >= 8 then r = URIutil.isISSNvalid( attempt ); elseif #s == 0 then r = 0; else r = false; end else r = false; end return r; end -- URIutil.mayISSN() function URIutil.mayLCCN( attempt ) -- Is this a syntactically correct LCCN? -- Precondition: -- attempt -- string with presumable LCCN -- Postcondition: -- Returns string with LCCN formatted aa9999-99999999 -- 0 if empty -- false if not recognized if type( attempt ) == "string" then local s = mw.text.trim( attempt ); if s == "" then r = 0; else r = URIutil.isLCCN( s ); end else r = false; end return r; end -- URIutil.mayLCCN() function URIutil.mayURI( attempt, ascii ) -- Is this a syntactically correct URI, or empty? -- Precondition: -- attempt -- string with presumable URI -- ascii -- limit to ASCII (no IRI) -- Postcondition: -- Returns false if no problem -- string with violation local r = URIutil.isEscValid( attempt ); if not r then local s = mw.text.trim( attempt ); r = s:match( "%s(.+)$" ); if not r then r = s:match( "#(.*)$" ); if r then r = "#" .. r; elseif ascii then local p = string.format( "[%s].+$", mw.ustring.char( 128,45,255 ) ); r = mw.ustring.match( s, p ); end end end return r; end -- URIutil.mayURI() function URIutil.mayURN( attempt ) -- Is this a syntactically correct URN, or empty? -- Precondition: -- attempt -- string with presumable URN, starting with "urn:" -- Postcondition: -- Returns false if no problem -- string with violation local r = URIutil.mayURI( attempt, true ); if not r then local s = attempt:match( "^%s*[uU][rR][nN]:(.+)$" ); if s then local space, id = s:match( "^(%w+):(.+)$" ); if space then r = URNnamespace( space:lower(), id ); else r = s; end elseif mw.text.trim( attempt ) == "" then r = false; else r = "urn:"; end end return r; end -- URIutil.mayURN() function URIutil.plainISBN( attempt ) -- Format ISBN as digits (and 'X') only string -- Precondition: -- attempt -- string with presumable ISBN -- Postcondition: -- Returns string with 10 or 13 chars -- false if not empty and not an ISBN local r; local isbn = ISBNfactory( attempt ); if type( isbn ) == "table" then r = ISBNflat( isbn ); else r = false; end return r; end -- URIutil.plainISBN() function URIutil.targetISSN( attempt, allow, any1, any2, alert ) -- Retrieve bracketed titled external link on ISSN DB without "ISSN" -- Precondition: -- attempt -- string with presumable ISSN -- allow -- true: permit invalid check digit -- any1 -- intentionally dummy parameter -- any2 -- intentionally dummy parameter -- alert -- string with title of maintenance category, or nil -- Postcondition: -- Returns link local cnf = fetch( "config" ); local issn = ISSNfactory( attempt ); local lapsus, r; if type( issn ) == "table" then local lenient; if type( allow ) == "string" then lenient = ( allow ~= "0" ); else lenient = allow; end if lenient then lapsus = false; else lapsus = ( not ISSNfaith( issn ) ); end r = ISSNformat( issn, issn.type ); if type( cnf.issn ) == "string" then r = string.format( "[%s %s]", cnf.issn:gsub( "%$1", r ), r ); end else lapsus = true; r = attempt; end if lapsus then r = string.format( "<span class='invalid-ISSN'>%s</span>%s", r, fault( "(?!?!)" ) ); if alert then r = r .. flop( alert ); end end return r; end -- URIutil.targetISSN() function URIutil.uriDOI( attempt, anything, abbr ) -- Retrieve linked URI on DOI resolver -- Precondition: -- attempt -- string with presumable DOI -- anything -- intentionally dummy parameter -- abbr -- true or string: link doi: abbreviation local r = URIutil.linkDOI( attempt ); if r then if abbr then local s; if type( abbr ) == "string" then s = abbr; else s = "Digital Object Identifier"; end r = string.format( "[[%s|doi]]:%s", s, r ); else r = "doi:" .. r; end end return r; end -- URIutil.uriDOI() function URIutil.uriHandle( attempt, anything, abbr ) -- Retrieve linked URI on handle resolver -- Precondition: -- attempt -- string with presumable handle -- anything -- intentionally dummy parameter -- abbr -- true or string: link hdl: abbreviation local r = URIutil.linkHandle( attempt ); if r then local s; if type( abbr ) == "string" then s = abbr; end if s then r = string.format( "[[%s|hdl]]:%s", s, r ); else r = "hdl:" .. r; end end return r; end -- URIutil.uriHandle() function URIutil.uriURN( attempt, anything, alter, alert ) -- Retrieve linked URI on URN resolver -- Precondition: -- attempt -- string with presumable URN, starting with "urn:" -- anything -- intentionally dummy parameter -- alter -- string with alternative handler, or nil -- alert -- string with title of maintenance category, or nil -- Postcondition: -- Returns link, or plain string if bad URN local r, l = URIutil.linkURN( attempt, alter, false, false, alert ); if l then local s = fetch( "config" ).supportURN; if s then if type( s ) ~= "string" or s == "" then s = false; end else s = "Uniform Resource Name"; end if s then r = string.format( "[[%s|urn]]:%s", s, r ); else r = "urn:" .. r; end end return r; end -- URIutil.uriURN() URIutil.failsafe = function ( assert ) local r; if not assert or assert <= URIutil.serial then r = URIutil.serial; else r = false; end return r; end -- URIutil.failsafe() local Template = function ( frame, action ) -- Retrieve library result for template access -- Precondition: -- frame -- object -- action -- string; function name -- Postcondition: -- Returns appropriate string, or error message (development) local lucky, r = pcall( URIutil[ action ], frame.args[ 1 ] or "", frame.args[ 2 ], faculty( frame.args.link, true ), faculty( frame.args.nbsp, true ), frame.args.cat ); if lucky then if r then r = tostring( r ); else r = ""; end else r = fault( r ); end return r; end -- Template() -- Provide template access and expose URIutil table to require() local p = {}; function p.coreISSN( frame ) return Template( frame, "coreISSN" ); end function p.formatISBN( frame ) return Template( frame, "formatISBN" ); end function p.formatISSN( frame ) return Template( frame, "formatISSN" ); end function p.formatLCCN( frame ) return Template( frame, "formatLCCN" ); end function p.isDNBvalid( frame ) return Template( frame, "isDNBvalid" ); end function p.isDOI( frame ) return Template( frame, "isDOI" ); end function p.isEscValid( frame ) return Template( frame, "isEscValid" ); end function p.isGTINvalid( frame ) return Template( frame, "isGTINvalid" ); end function p.isHandle( frame ) return Template( frame, "isHandle" ); end function p.isISBN( frame ) return Template( frame, "isISBN" ); end function p.isISBNvalid( frame ) return Template( frame, "isISBNvalid" ); end function p.isISSNvalid( frame ) return Template( frame, "isISSNvalid" ); end function p.isLCCN( frame ) return Template( frame, "isLCCN" ); end function p.linkDNBopac( frame ) return Template( frame, "linkDNBopac" ); end function p.linkDOI( frame ) return Template( frame, "linkDOI" ); end function p.linkDOI( frame ) return Template( frame, "linkDOI" ); end function p.linkHandle( frame ) return Template( frame, "linkHandle" ); end function p.linkISBN( frame ) return Template( frame, "linkISBN" ); end function p.linkISSN( frame ) return Template( frame, "linkISSN" ); end function p.linkLCCN( frame ) return Template( frame, "linkLCCN" ); end function p.linkURN( frame ) return Template( frame, "linkURN" ); end function p.mayDOI( frame ) return Template( frame, "mayDOI" ); end function p.mayHandle( frame ) return Template( frame, "mayHandle" ); end function p.mayISBN( frame ) return Template( frame, "mayISBN" ); end function p.mayISSN( frame ) return Template( frame, "mayISSN" ); end function p.mayLCCN( frame ) return Template( frame, "mayLCCN" ); end function p.mayURI( frame ) return Template( frame, "mayURI" ); end function p.mayURN( frame ) return Template( frame, "mayURN" ); end function p.plainISBN( frame ) return Template( frame, "plainISBN" ); end function p.targetISSN( frame ) return Template( frame, "targetISSN" ); end function p.uriDOI( frame ) return Template( frame, "uriDOI" ); end function p.uriHandle( frame ) return Template( frame, "uriHandle" ); end function p.uriURN( frame ) return Template( frame, "uriURN" ); end p.failsafe = function ( frame ) local s = type( frame ); local since; if s == "table" then since = frame.args[ 1 ]; elseif s == "string" then since = frame; end if since then since = mw.text.trim( since ); if since == "" then since = false; end end return URIutil.failsafe( since ) or ""; end -- p.failsafe() function p.URIutil( arg ) local r; if arg then r = ""; else r = URIutil; end return r; end return p;