Модуль:ФИО: различия между версиями

Материал из Кадровый состав НКВД 1935-1939
Перейти к навигации Перейти к поиску
Нет описания правки
Нет описания правки
(не показано 8 промежуточных версий этого же участника)
Строка 1: Строка 1:
local pp = {}
local p = {}
local global = mw.ext.luaglobal;
local global = mw.ext.luaglobal;
local tools = require( 'Модуль:Tools' )
local tools = require( 'Модуль:Tools' )
local cq = mw.ext.cargo.query
global.strict( true )
global.strict( true )


local argus = { true, '', '', '', ['дополнение'] = '', ['сноска'] = '', ['источник'] = '', }
local argus = { true, true, true, true, ['дополнение'] = '', ['сноска'] = '', ['источник'] = '', }
pp[''] = function ( frame )
p[''] = function ( frame )
local args, tmp = tools.checkargs( frame:getParent().args, argus )
local args, tmp = tools.checkargs( frame:getParent().args, argus )
local ourPage = mw.title.getCurrentTitle().text
local ourPage = mw.title.getCurrentTitle().text
Строка 13: Строка 14:
.. 'дополнение = <var>текст</var> | сноска =  <var>текст</var> | '
.. 'дополнение = <var>текст</var> | сноска =  <var>текст</var> | '
.. 'источник = <var>текст</var> }}'
.. 'источник = <var>текст</var> }}'
local errorPageName = 'Первый вызов шаблона ФИО должен соответствовать '
     if not args then
.. 'имени персоналии в заголовке страницы'
     if not args then  
return tools.errorMsg( 'ФИО', 'Неизвестный параметр ' .. tmp, errorAdvice )
return tools.errorMsg( 'ФИО', 'Неизвестный параметр ' .. tmp, errorAdvice )
     end
     end
local fa = args[1]
local fa, im, ot, idx
fa = args[1]
if not fa then
if not fa then
return tools.errorMsg( 'ФИО', 'Не указана фамилия', errorAdvice )
return tools.errorMsg( 'ФИО', 'Не указана фамилия', errorAdvice )
end
end
 
local gFIO = global.get( 'gFIO' )
-- изменения:
-- * индекс обязателен даже у первого вызова (чтобы при переименованиях не потерялось)
-- Варианты: {ф и о} {ф и о|индекс} {ф и о индекс} {ф|и|о} {ф|и|о|индекс}
-- * Вариант: {ф и о|индекс} убираем за бессмысленностью. Либо единое поле, либо поэлементно
local im = args[2]
 
local idx = ''
if args[2] == '-' then -- старый способ указания корейца
if string.sub( im, 1, 1 ) == '(' then
fa = fa .. ', '
im, idx = '', im
args[2] = nil
end
end
local ot = args[3]
-- Если у нас единое поле, то надо разбить на fa-im-ot-idx
tmp = args[4]
if #args == 1 then
if tmp ~= '' then
-- прежде всего делим по запятой: до запятой фамилия
if string.sub( tmp, 1, 1 ) ~= '(' or  idx ~= '' then
tmp = mw.text.split( fa .. ' ', ', ' ) -- пробел добавили для концевой запятой
return tools.errorMsg( 'ФИО', 'Ошибка в номере тезки', errorAdvice )
if #tmp > 2 then
return tools.errorMsg( 'ФИО',
'Запятая используется только для отделения фамилии от имени-отчества',
errorAdvice )
end
end
idx = tmp
tmp[#tmp] = mw.text.trim( tmp[#tmp] )
end
if #tmp == 2 then
if im == '' then
fa = tmp[1]
tmp = mw.ustring.find( fa, '(', 1, true )
tmp = mw.text.split( tmp[2], ' ' )
if tmp then
else
fa, idx = mw.text.trim( mw.ustring.sub( fa, 1, tmp-1 ) ), mw.ustring.sub( fa, tmp, -1 )
tmp = mw.text.split( tmp[1], ' ' )
fa = tmp[1]
table.remove( tmp, 1 )
end
 
idx = tmp[#tmp]
if string.match( idx, '^%([IVX]+%)$' ) then
tmp[#tmp] = nil
else
idx = nil
end
end
local fio = mw.text.split( fa, '[\t\r\n\f ]+', false )
 
if #fio > 3 then
if #tmp > 2 then
return tools.errorMsg( 'ФИО',  
return tools.errorMsg( 'ФИО',
'Если какая-то часть ФИО содержит несколько слов, разделяйте части символом «|»',  
'Если какая-то часть ФИО содержит несколько слов, разделяйте части символом «|» ' .. (fa or '—') .. '\n' .. mw.dumpObject(tmp),
errorAdvice )
errorAdvice )
end
if #fio == 1 then
return tools.errorMsg( 'ФИО', 'Задана только фамилия. Если имени действительно нет, то поставьте вместо него знак «-»', errorAdvice )
end
end
if mw.ustring.sub( fio[1], -1, -1) == ',' then
im, ot = tmp[1], tmp[2]
fio[1] = mw.ustring.sub( fio[1], 1, -2)
if im == '' then
im = nil
end
end
fa, im, ot = fio[1], fio[2], fio[3]
end
if not  mw.ustring.match( fa, '^[А-Яа-яЁё%- ]+$' ) then
return tools.errorMsg( 'ФИО', 'Недопустимые символы в фамилии', errorAdvice )
end
if not ( mw.ustring.match( im, '^[А-Яа-яЁё%- ]+$' )
or mw.ustring.match( im, '^[А-ЯЁ%-]%.$' ) ) then
return tools.errorMsg( 'ФИО', 'Недопустимые символы в имени', errorAdvice )
end
if not ( mw.ustring.match( ot, '^[А-Яа-яЁё%- ]*$' )
or mw.ustring.match( ot, '^[А-ЯЁ%-]%.$' ) ) then
return tools.errorMsg( 'ФИО', 'Недопустимые символы в отчестве', errorAdvice )
end
local fio
if im == '-' then
fio = fa -- китаец
im = ''
else
else
fio = mw.text.trim( fa .. ', ' .. im .. ' ' .. ot )
im, ot, idx = args[2], args[3], args[4]
end
if idx and not string.match( idx, '%([IVX]+%)' ) then
return tools.errorMsg( 'ФИО',
if not gFIO then
'Номер тезки должен указываться в скобках римскими цифрами',
-- первый шаблон ФИО на странице. Может отличаться от заголовка только
errorAdvice )
-- отсутствием индекса тезки (чтобы при переименовании страницы для
-- добавления индекса не нужно было править содержимое страницы)
if ourPage ~= fio then
local pageIdx = mw.ustring.find( ourPage, '(', 1, true )
if pageIdx then
pageIdx = mw.ustring.sub( ourPage, pageIdx, -1 )
else
return tools.errorMsg( 'ФИО', errorPageName, errorAdvice )
end
if idx ~= '' and idx ~= pageIdx then
return tools.errorMsg( 'ФИО', errorPageName, errorAdvice )
end
idx = pageIdx
end
if idx ~= '' then
frame:callParserFunction{ name = 'DISPLAYTITLE', 
args = fio .. ' <span class="nkvd-idx">' .. idx .. '</span>' }
end
end
--@TODO для псевдонимов надо проверять дублирование на самой странице!
end
end
-- Проверка тезок
local crA, crB, crC, crD
--
local namesakes = {}
-- tmp = frame:callParserFunction{ name = '#cargo_query', args = { '',
-- tables      = 'names',
-- where        = 'name="' .. fio .. '"',
-- fields      = 'disambig, CONCAT(_pageName)=pn',
-- ['order_by'] = 'disambig',
-- limit        = '999',
-- format      = 'native',
-- } }
-- local qres = mw.ext.cargo.get()
local qres = tools.cq( 'names', 'disambig, _pageName', {
where        = 'name="' .. fio .. '"',
orderBy      = 'disambig',
limit        = '999',
} )
if qres then
for _, namesake in ipairs( qres ) do
local id = namesake.disambig
namesakes[id] = namesake._pageName
if id ~= '' and id ~= idx then
crC = true
end
end
end


-- здесь у нас fa-im-ot-idx. Запятой нет, idx корректен, в остальном ФИО не проверено
-- Проверка корректности




crA = namesakes[''] ~= nil
local gFIO = global.get( 'gFIO' )
crB = ( namesakes[idx] or ourPage ) ~= ourPage
if not gFIO then
crD = mw.title.new( fio ).exists
-- Перед дальнейшими преобразованиями сверимся с заголовком страницы
local actionIdx = 0  -- 1 - укажите индекс, 2 - измените индекс
tmp = { fa .. ',' }
local actionAlt = 0  -- 1 - переименуйте страницу, 2 — отредактируйте страницу
tmp[#tmp+1] = im
local actionDis = 0  -- 1 — создайте страницу разрешения неоднозначностей
tmp[#tmp+1] = ot
local debugFio = '(' .. ourPage .. '/' .. fio  .. ':' .. idx .. ':' .. tostring( crA ) .. ' ' .. tostring( crB ) .. ' ' .. tostring( crC ) .. ' ' .. tostring( crD ) .. ') ' .. mw.dumpObject( qres ) .. '\n'
tmp[#tmp+1] = idx
if idx == '' then
local tmp1 = table.concat( tmp, ' ' )
if     not crB and not crC then
if not im and not ot then
elseif not crB and    crC then
tmp[1] = fa
actionIdx = 1
tmp = table.concat( tmp, ' ' )
if not crD then
else
actionDis = 1
tmp = nil
end
elseif    crB and not crC then
if crD then
actionAlt = 2
else
actionAlt = 1
end
actionIdx = 1
actionDis = 1
else --    crB and    crC then
error( 'Ошибка алгоритма' )
end
end
elseif not crA and not crB then
if ourPage ~= tmp1 and ourPage ~= tmp then
if not crD then
return tools.errorMsg( 'ФИО',
actionDis = 1
'Первый вызов шаблона ФИО должен соответствовать заголовку страницы',
errorAdvice )
end
end
elseif not crA and crB then
frame:callParserFunction{ name = 'DISPLAYTITLE',
actionIdx = 2
args = tools.name( ourPage ) }
if not crD then
end
actionDis = 1
ot = ot or ''
end
im = im or ''
elseif crA and not crB and not crC then
-- поверхностная проверка имени
if crD then
if not mw.ustring.match( fa..im..ot, '^[А-Яа-я%- %.]+$' ) then
actionAlt = 2
return tools.errorMsg( 'ФИО',
else
'Имя может содержать только русские буквы',
actionAlt = 1
errorAdvice )
end
actionDis = 1
else
error( 'Ошибка алгоритма' )
end
end
--TODO:  проверка на кызы-оглы-заде, (нужна для псевдонимов, даже если она есть в newarticletext)


local txtErr,txtAdv = '', ''
tmp = im .. ' ' .. ot
if actionIdx ~= 0 then
tmp = string.gsub( tmp, '%-%.', '' )
if actionIdx == 1 then
tmp = string.gsub( tmp, '%.%.%.', '' )
actionIdx = ''
tmp = string.gsub( tmp, '%.', '' )
else
--@TODO заменить Ё на Е
actionIdx = 'другой (свободный) '
local im2 = string.find( tmp .. ' ', ' ', 1, true )
end
local im1 = string.sub( tmp, 1, im2 - 1 )
if gFIO then
im2 = mw.text.trim( string.sub( tmp, im2+1, -1) ) -- если отчества не было, а имя двойное, то может быть пробел в конце
txtErr = 'изменить вызов шаблона ФИО'
 
else
local query = cq(
txtErr = 'переименовать данную страницу'
'names_table',
end
'_pageName, lastN, firstN, middleN, disambig',
txtErr = 'Необходимо ' .. txtErr .. ', указав ' .. actionIdx
{
.. '«индекс тезки»'
where = 'lastN="' .. fa .. '" AND firstN="' .. im1
if actionDis ~= 0 then
.. '" AND middleN="' .. im2 .. '"',
txtErr = txtErr .. ' — скорее всего, «(II)»'
}
end
)
if actionAlt ~= 0 then
local namesakes = {}
txtAdv = 'После этого будет необходимо переименовать/отредактировать страницу тезки'
for _, row in pairs( query ) do
if actionDis ~= 0 then
namesakes[row.disambig or '' ] = row
txtAdv = txtAdv .. ' и создать страницу разрешения неоднозначностей'
end
end
tmp = namesakes[idx or '']
elseif actionDis ~= 0 then
if tmp and tmp._pageName ~= ourPage then
txtAdv = 'После этого будет необходимо создать страницу разрешения неоднозначностей'
return tools.errorMsg( 'ФИО',
end
'Указанное имя персоналии относится к [[' .. tmp._pageName
elseif actionAlt == 2 then
.. '|другому лицу]]',
txtErr = 'Необходимо перейти по этой [[Special:MovePage/' .. fio
errorAdvice )
.. '|ссылке]], чтобы переименовать ранее созданную страницу с именем «'  
end
.. fio ..'» в «' .. fio ..' (I)»'
if idx and namesakes[''] then
txtAdv = 'Страница «' .. fio
return tools.errorMsg( 'ФИО',
..'» будет использоваться как указатель для разрешения неоднозначности'
'При наличии тезок [[' .. namesakes['']._pageName
elseif actionAlt == 1 then
.. '|соответствующее имя без указания номера]]'
txtErr = 'Необходимо перейти на ['
.. ' должно относиться к странице разрешения неоднозначности',
.. tostring( mw.uri.fullUrl( namesakes[''], {
errorAdvice )
action = 'edit',
end
editintro = 'Template:Disambiguation_renumber_editnotice',
if not idx and ( #query > 1 or ( #query == 1 and query[1].disambig ~= '' ) ) then
para = fio
return tools.errorMsg( 'ФИО',
} ) )
'Указанное имя уже использовалось на других страницах с индексами.'
.. ' страницу], где имя «' .. fio ..'» указано в качестве псевдонима'
.. ' Поэтому без индекса его можно использовать только для страницы разрешения неоднозначности',
.. ' в одном из шаблонов ФИО, чтобы добавить к нему индекс тезки «(I)»'
errorAdvice )
if actionDis ~= 0 then
txtAdv = 'После этого будет необходимо создать страницу разрешения неоднозначностей'
end
elseif actionDis ~= 0 then
txtErr = 'Необходимо перейти по этой ['
.. tostring( mw.uri.fullUrl( fio, {
action = 'edit',
preload = 'Template:Disambiguation_pattern',
editintro = 'Template:Disambiguation_editnotice'
} ) )
.. ' ссылке], чтобы создать страницу разрешения неоднозначностей'
end
if txtErr ~= '' then
return tools.errorMsg ( 'ФИО', txtErr, txtAdv )
-- .. '\n' .. debugFio )
end
end
local addendum, comment, source =
 
args['дополнение'] or '', args['сноска'] or '', args['источник'] or ''
 
 
if not gFIO then
if not gFIO then
gFIO = {}
gFIO = {}
end
end
table.insert( gFIO, { fa, im, ot, idx, addendum, comment, source } )
table.insert( gFIO, { l = fa, i = im, o = ot, d = idx, f = im1, m = im2,
a = args['дополнение'], r = args['сноска'], s = args['источник'],  } )
global.set( 'gFIO', gFIO )
global.set( 'gFIO', gFIO )
-- ставим вызов Cargo в return, чтобы не потерять сообщения об ошибках
 
return frame:expandTemplate{ title = 'Таблица ФИО', args = {
return frame:expandTemplate{ title = 'Cargo:Names', args = {
name = fio,
lastN    = fa,
disambig = idx,
firstN    = im1,
addendum = addendum,
middleN  = im2,
} } .. '<i></i>'  
disambig = idx,
addendum = args['дополнение'],
porno    = #gFIO,    --TODO: если это убрать, то можно не проверять на дубликаты
} } .. '<i></i>'
--[[
.. '<i class="nkvd-hide-link">[ «' .. fa .. '» | «'
.. ( im or '—' ) .. '» : «' .. ( ot or '—' ) .. '» | «'
.. ( im1 or '—' ) .. '» : «' .. ( im2 or '—' ).. '» | «'
.. ( idx or '—' ) .. '» ] </i>'
--]]
 
 
 
 
end
end


return pp
return p

Версия от 20:13, 27 января 2018

Для документации этого модуля может быть создана страница Модуль:ФИО/doc

local p = {}
local global = mw.ext.luaglobal;
local tools = require( 'Модуль:Tools' )
local cq = mw.ext.cargo.query
global.strict( true )

local argus = { true, true, true, true, ['дополнение'] = '', ['сноска'] = '', ['источник'] = '', }
p[''] = function ( frame )
	local args, tmp = tools.checkargs( frame:getParent().args, argus )
	local ourPage = mw.title.getCurrentTitle().text
	local errorAdvice = 'Используйте формат {{ ФИО | <var>Фамилия</var> | '
		.. '<var>Имя</var> | <var>Отчество</var>  | '
		.. '<var>номер тезки в скобках при наличии</var> | '
		.. 'дополнение = <var>текст</var> | сноска =  <var>текст</var> | '
		.. 'источник = <var>текст</var> }}'
    if not args then
		return tools.errorMsg( 'ФИО', 'Неизвестный параметр ' .. tmp, errorAdvice )
    end
	local fa, im, ot, idx
	fa = args[1]
	if not fa then
		return tools.errorMsg( 'ФИО', 'Не указана фамилия', errorAdvice )
	end

	-- изменения:
	-- * индекс обязателен даже у первого вызова (чтобы при переименованиях не потерялось)
	-- * Вариант: {ф и о|индекс} убираем за бессмысленностью. Либо единое поле, либо поэлементно

	if args[2] == '-' then -- старый способ указания корейца
		fa = fa .. ', '
		args[2] = nil
	end
	-- Если у нас единое поле, то надо разбить на fa-im-ot-idx
	if #args == 1 then
		-- прежде всего делим по запятой: до запятой фамилия
		tmp = mw.text.split( fa .. ' ', ', ' ) -- пробел добавили для концевой запятой
		if #tmp > 2 then
			return tools.errorMsg( 'ФИО',
				'Запятая используется только для отделения фамилии от имени-отчества',
				errorAdvice )
		end
		tmp[#tmp] = mw.text.trim( tmp[#tmp] )
		if #tmp == 2 then
			fa = tmp[1]
			tmp = mw.text.split( tmp[2], ' ' )
		else
			tmp = mw.text.split( tmp[1], ' ' )
			fa = tmp[1]
			table.remove( tmp, 1 )
		end

		idx = tmp[#tmp]
		if string.match( idx, '^%([IVX]+%)$' ) then
			tmp[#tmp] = nil
		else
			idx = nil
		end

		if #tmp > 2 then
			return tools.errorMsg( 'ФИО',
				'Если какая-то часть ФИО содержит несколько слов, разделяйте части символом «|» ' .. (fa or '—') .. '\n' .. mw.dumpObject(tmp),
				errorAdvice )
		end
		im, ot = tmp[1], tmp[2]
		if im == '' then
			im = nil
		end
	else
		im, ot, idx = args[2], args[3], args[4]
		if idx and not string.match( idx, '%([IVX]+%)' ) then
			return tools.errorMsg( 'ФИО',
				'Номер тезки должен указываться в скобках римскими цифрами',
				errorAdvice )
		end
	end

	-- здесь у нас fa-im-ot-idx. Запятой нет, idx корректен, в остальном ФИО не проверено
	-- Проверка корректности


	local gFIO = global.get( 'gFIO' )
	if not gFIO then
		-- Перед дальнейшими преобразованиями сверимся с заголовком страницы
		tmp = { fa .. ',' }
		tmp[#tmp+1] = im
		tmp[#tmp+1] = ot
		tmp[#tmp+1] = idx
		local tmp1 = table.concat( tmp, ' ' )
		if not im and not ot then
			tmp[1] = fa
			tmp = table.concat( tmp, ' ' )
		else
			tmp = nil
		end
		if ourPage ~= tmp1 and ourPage ~= tmp then
			return tools.errorMsg( 'ФИО',
				'Первый вызов шаблона ФИО должен соответствовать заголовку страницы',
				errorAdvice )
		end
		frame:callParserFunction{ name = 'DISPLAYTITLE',
			args = tools.name( ourPage ) }
	end
	ot = ot or ''
	im = im or ''
	-- поверхностная проверка имени
	if not mw.ustring.match( fa..im..ot, '^[А-Яа-я%- %.]+$' ) then
		return tools.errorMsg( 'ФИО',
			'Имя может содержать только русские буквы',
			errorAdvice )
	end
	--TODO:  проверка на кызы-оглы-заде, (нужна для псевдонимов, даже если она есть в newarticletext)

	tmp = im .. ' ' .. ot
	tmp = string.gsub( tmp, '%-%.', '' )
	tmp = string.gsub( tmp, '%.%.%.', '' )
	tmp = string.gsub( tmp, '%.', '' )
	--@TODO заменить Ё на Е
	local im2 = string.find( tmp .. ' ', ' ', 1, true )
	local im1 = string.sub( tmp, 1, im2 - 1 )
	im2 = mw.text.trim( string.sub( tmp, im2+1, -1) ) -- если отчества не было, а имя двойное, то может быть пробел в конце

	local query = cq(
			'names_table',
			'_pageName, lastN, firstN, middleN, disambig',
			{
				where = 'lastN="' .. fa .. '" AND firstN="' .. im1
					.. '" AND middleN="' .. im2 .. '"',
			}
		)
	local namesakes = {}
	for _, row in pairs( query ) do
		namesakes[row.disambig or '' ] = row
	end
	tmp = namesakes[idx or '']
	if tmp and tmp._pageName ~= ourPage then
		return tools.errorMsg( 'ФИО',
			'Указанное имя персоналии относится к [[' .. tmp._pageName
				.. '|другому лицу]]',
			errorAdvice )
	end
	if idx and namesakes[''] then
		return tools.errorMsg( 'ФИО',
			'При наличии тезок [[' .. namesakes['']._pageName
				.. '|соответствующее имя без указания номера]]'
				.. ' должно относиться к странице разрешения неоднозначности',
			errorAdvice )
	end
	if not idx and ( #query > 1 or ( #query == 1 and query[1].disambig ~= ''  ) ) then
		return tools.errorMsg( 'ФИО',
			'Указанное имя уже использовалось на других страницах с индексами.'
				..	' Поэтому без индекса его можно использовать только для страницы разрешения неоднозначности',
			errorAdvice )
	end



	if not gFIO then
		gFIO = {}
	end
	table.insert( gFIO, { l = fa, i = im, o = ot, d = idx, f = im1, m = im2,
		a = args['дополнение'], r = args['сноска'], s = args['источник'],  } )
	global.set( 'gFIO', gFIO )

	return frame:expandTemplate{ title = 'Cargo:Names', args = {
			lastN     = fa,
			firstN    = im1,
			middleN   = im2,
			disambig  = idx,
			addendum  = args['дополнение'],
			porno     = #gFIO,    --TODO: если это убрать, то можно не проверять на дубликаты
		} } .. '<i></i>'
--[[
			.. '<i class="nkvd-hide-link">[ «' .. fa .. '» | «'
			.. ( im or '—' ) .. '» : «' .. ( ot or '—' ) .. '» | «'
			.. ( im1 or '—' ) .. '» : «' .. ( im2 or '—' ).. '» | «'
			.. ( idx or '—' ) .. '» ] </i>'
--]]




end

return p