Zum Inhalt springen

Modul:VisualEditorRef

aus Wikipedia, der freien Enzyklopädie
Vorlagenprogrammierung Diskussionen Lua Unterseiten
Modul Deutsch English

Modul: Dokumentation

Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus

Modul für mw:Help:Cite/VisualEditor reference names – extrahiert Inhalte aus typischen Vorlagenparametern bei {{Internetquelle}}, {{Literatur}} und anderen Vorlagen via {{AutonameInternetquelle}}, {{AutonameLiteratur}} und {{Autoname}}.


local p = {}

local function trim(value)
    return mw.text.trim(tostring(value or ''))
end

-- Extract the first four-digit year from a date string.
local function extractYear(value)
    return trim(value):match('(%d%d%d%d)')
end

-- Get the year from German or English date/year parameters.
local function getYear(args, germanFirst)
    local fields

    if germanFirst then
        fields = { 'Datum', 'Jahr', 'datum', 'jahr', 'date', 'year' }
    else
        fields = { 'date', 'year', 'Datum', 'Jahr', 'datum', 'jahr' }
    end

    for _, field in ipairs(fields) do
        local value = trim(args[field])
        if value ~= '' then
            local year = extractYear(value)
            if year then
                return year
            end
        end
    end

    return nil
end

-- Ensure every non-empty base name ends with a dash.
local function withDash(name)
    name = trim(name)
    if name == '' then
        return ''
    end

    if name:sub(-1) ~= '-' then
        return name .. '-'
    end

    return name
end

-- Append the year when available, and always end with a dash.
local function withYear(name, args, germanFirst)
    if name == '' then
        return ''
    end

    local year = getYear(args, germanFirst)
    if year then
        name = name .. year
    end

    return withDash(name)
end

-- Extract the surname from the first author/editor.
-- Optimized for formats such as "Petra Meier, Paul Schulz".
local function extractSurname(value)
    value = trim(value)
    if value == '' then
        return ''
    end

    -- Keep only the first author when authors are comma-separated.
    value = value:match('^([^,]+)') or value
    value = trim(value)

    -- Use the last word of the first author's name.
    return value:match('([^%s]+)$') or value
end

-- Extract a domain from a URL or a bare domain name.
-- When an archive URL contains the original URL, prefer the
-- last embedded HTTP(S) URL.
local function extractDomain(value)
    value = trim(value)
    if value == '' then
        return ''
    end

    local candidate

    for found in mw.ustring.gmatch(value, 'https?://[^%s<>"]+') do
        candidate = found
    end

    candidate = candidate or value

    -- Remove punctuation commonly attached to URLs in text.
    candidate = candidate:gsub('[%)%]%}>,;%.]+$', '')

    local host = candidate:match(
        '^[%a][%w+.-]*://([^/%?#]+)'
    )

    if not host then
        host = candidate:match('^//([^/%?#]+)')
    end

    -- Accept bare domains such as example.com or tagesschau.de.
    if not host then
        host = candidate:match(
            '^([%w][%w.-]*%.[%a][%a%.%-]*)[%:%/%?#]*$'
        )
    end

    if not host then
        return ''
    end

    host = host:lower()
    host = host:match('([^@]+)$') or host
    host = host:gsub(':%d+$', '')
    host = host:gsub('^www%.', '')

    -- Reject values that don't look like a hostname.
    if not host:find('%.') or host:find('%.%.') then
        return ''
    end

    return host
end

-- Extract the longest word from a title or other descriptive value.
-- Prefer a word beginning with an uppercase letter when available.
local function extractTitleWord(value)
    value = trim(value)
    if value == '' then
        return ''
    end

    local longest = ''
    local longestCapitalized = ''

    for word in mw.ustring.gmatch(value, '%S+') do
        word = mw.ustring.gsub(word, '^[%p]+', '')
        word = mw.ustring.gsub(word, '[%p]+$', '')

        if mw.ustring.len(word) > mw.ustring.len(longest) then
            longest = word
        end

        if mw.ustring.match(word, '^%u')
            and mw.ustring.len(word) >
                mw.ustring.len(longestCapitalized) then
            longestCapitalized = word
        end
    end

    if longestCapitalized ~= '' then
        return longestCapitalized
    end

    return longest
end

-- Use a title-like value: domain first, otherwise longest word.
local function extractDescriptiveValue(value)
    value = trim(value)
    if value == '' then
        return ''
    end

    local domain = extractDomain(value)
    if domain ~= '' then
        return domain
    end

    return extractTitleWord(value)
end

-- Try author/editor parameters in priority order.
local function findPerson(args, fields, germanFirst)
    for _, field in ipairs(fields) do
        local value = trim(args[field])
        if value ~= '' then
            local name = extractSurname(value)
            if name ~= '' then
                return withYear(name, args, germanFirst)
            end
        end
    end

    return ''
end

-- Try descriptive parameters in priority order.
local function findDescription(args, fields)
    for _, field in ipairs(fields) do
        local value = trim(args[field])
        if value ~= '' then
            local name = extractDescriptiveValue(value)
            if name ~= '' then
                return withDash(name)
            end
        end
    end

    return ''
end

-- Internetquelle:
-- url -> autor (+ datum) -> titel -> werk
function p.internetquelle(frame)
    local args = frame.args

    -- Prefer the URL if present and extract its domain.
    local url = trim(args.url)
    if url ~= '' then
        local domain = extractDomain(url)
        if domain ~= '' then
            return withDash(domain)
        end
    end

    -- Fall back to the author, with date/year if available.
    local name = findPerson(args, { 'autor' }, true)
    if name ~= '' then
        return name
    end

    -- Then try the title, followed by the work.
    return findDescription(args, {
        'titel',
        'werk'
    })
end

-- Literatur:
-- Autor (+ Datum/Jahr) -> Titel -> Hrsg (+ Datum/Jahr)
-- -> Sammelwerk
function p.literatur(frame)
    local args = frame.args

    -- Prefer the author.
    local name = findPerson(args, { 'Autor' }, true)
    if name ~= '' then
        return name
    end

    -- Then try the title.
    name = findDescription(args, { 'Titel' })
    if name ~= '' then
        return name
    end

    -- Then the editor, with date/year if available.
    name = findPerson(args, { 'Hrsg' }, true)
    if name ~= '' then
        return name
    end

    -- Finally, try the collected work.
    return findDescription(args, { 'Sammelwerk' })
end

-- Generic fallback:
-- German author -> English author fields -> editor fields
-- -> URL -> titles/text -> publication/work fields.
function p.fallback(frame)
    local args = frame.args

    local name = findPerson(args, {
        'Autor',
        'autor'
    }, true)
    if name ~= '' then
        return name
    end

    name = findPerson(args, {
        'authors'
    }, false)
    if name ~= '' then
        return name
    end

    name = findPerson(args, {
        'last'
    }, false)
    if name ~= '' then
        return name
    end

    name = findPerson(args, {
        'last1'
    }, false)
    if name ~= '' then
        return name
    end

    name = findPerson(args, {
        'author'
    }, false)
    if name ~= '' then
        return name
    end

    name = findPerson(args, {
        'author1'
    }, false)
    if name ~= '' then
        return name
    end

    name = findPerson(args, {
        'Hrsg',
        'hrsg'
    }, true)
    if name ~= '' then
        return name
    end

    name = findPerson(args, {
        'editor',
        'editor1',
        'editor-last',
        'editor-last1'
    }, false)
    if name ~= '' then
        return name
    end

    name = findDescription(args, {
        'url',
        'URL'
    })
    if name ~= '' then
        return name
    end

    name = findDescription(args, {
        'Titel',
        'titel',
        'title',
        'text'
    })
    if name ~= '' then
        return name
    end

    return findDescription(args, {
        'werk',
        'work',
        'website',
        'journal',
        'Sammelwerk',
        'sammelwerk',
        'Suchbegriff',
        'Linktext',
        'publisher',
        'archive-url',
        'archiv-url'
    })
end

return p