Модуль:PersTools

Материал из Кадровый состав НКВД 1935-1939
Перейти к навигации Перейти к поиску

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

local perstools = {}

function perstools.makePersonLink( row )
	local person, i, o, d = row.nLast, row.nFirst, row.nMiddle, row.nDisambig
	if i ~= '' or o ~= '' then
		person = person .. ', '
		if ( i or '' ) == '' then
--			i = '...'
			i = '-.'
		elseif mw.ustring.len( i ) == 1 then
			i = i .. '.'
		end
		person = person .. i
		if ( o or '' ) ~= '' then
			if mw.ustring.len( o ) == 1 then
				o = o .. '.'
			end
			person = person .. ' ' .. o
		end
	end
	if ( d or '' ) ~= '' then
		local ds = d
--		if d == '(*)' then
--			ds = '<i class="fa fa-asterisk fa-lg"></i>'
--		end
		return '[[' .. person .. ' ' .. d .. '|'
			.. person .. ' <span class="nkvd-idx">' .. ds .. '</span>]]'
	end
	return '[[' .. person .. ']]'
end

local function altLast( f, similarTable )
	local alt = { f }
	local notAlt = {}
	local function addSimilar( str )
		if similarTable.simLast[str] then
			for _, sim in ipairs( similarTable.lastArray[similarTable.simLast[str]] ) do
				table.insert( alt, sim )
			end
		end
		if similarTable.notLast[str] then
			table.insert( notAlt, similarTable.notLast[str] )
		end
	end

	-- разбираем двойную фамилию или предполагаем, что фамилия может быть двойной
	local twin, twin2 = string.match( f, '(.+)%-(.+)' )
	if twin then
		table.insert( alt, twin )
		table.insert( alt, twin2 )
		table.insert( alt, twin2 .. '-' .. twin )
		addSimilar( twin )
		addSimilar( twin2 )
	else
		addSimilar( f )
	end


	local alt2 = {}
	for _, f in ipairs( alt ) do
		local tail = mw.ustring.sub( f, -4, -1 )
		local altTails = similarTable.tails[tail]
		if not altTails then
			tail = mw.ustring.sub( f, -3, -1 )
			altTails = similarTable.tails[tail]
			if not altTails then
				tail = mw.ustring.sub( f, -2, -1 )
				altTails = similarTable.tails[tail]
				if not altTails then
					tail = mw.ustring.sub( f, -1, -1 )
					altTails = similarTable.tails[tail]
					if not altTails then
						tail = ''
						altTails = similarTable.tails['']
					end
				end
			end
		end


		local body = mw.ustring.sub( f, 1, - mw.ustring.len( tail ) - 1 )
		local subst = mw.ustring.gsub( body, '[аоеийышщШЩБВ]', { ['а'] = '[ао]', ['о'] = '[ао]', ['е'] = '[еи]', ['и'] = '[еиый]', ['ы'] = '[ыие]', ['й'] = '[еий]',
				['ш'] = '[шщ]', ['щ'] = '[шщ]', ['Ш'] = '[ШЩ]', ['Щ'] = '[ШЩ]', ['Б'] = '[БВ]', ['В'] = '[БВ]', } )
		subst = mw.ustring.gsub( subst, '[дт]с', 'ц' )
		subst = mw.ustring.gsub( subst, 'лл', 'л' )
		subst = mw.ustring.gsub( subst, 'мм', 'м' )
		subst = mw.ustring.gsub( subst, 'нн', 'н' )
		subst = mw.ustring.gsub( subst, 'сс', 'с' )
		subst = mw.ustring.gsub( subst, 'зь?м', 'Зь?М' ) -- используем то, что в Lua поиск регистро-зависимый, а в SQL нет
		subst = mw.ustring.gsub( subst, '[сз]', '[сз]с?' )
		subst = mw.ustring.gsub( subst, 'л', 'лл?' )
		subst = mw.ustring.gsub( subst, 'м', 'мм?' )
		subst = mw.ustring.gsub( subst, 'н', 'н+' )
		subst = mw.ustring.gsub( subst, 'н%+ь?%[шщ%]', 'н+ь?[шщ]' )
		subst = mw.ustring.gsub( subst, 'ц', '(ц|тс|дс)' )
		alt2[subst .. '(' .. altTails .. ')'] = true
	end
	local altRes = {}

	for altPtn in pairs( alt2 ) do
		-- из-за этого не ловятся персонажи с ошибкой в одной из частей двойной фамилии
		if twin then
			table.insert( altRes, altPtn )
		else
			table.insert( altRes, altPtn .. '(-.+)?' )
			table.insert( altRes, '(.+-)?' .. altPtn )
		end
	end
	if next( notAlt ) then
		notAlt = table.concat( notAlt, ', ' )
	else
		notAlt = nil
	end
	return altRes, notAlt
end

function perstools.searchSimilar( f, i, o )
	local similarTable = require( 'Module:SimilarTable' )
	local fPatterns, fExclude = altLast( f, similarTable )
	if fExclude then
		fExclude = ' AND fio_f NOT IN ( ' .. fExclude .. ' )'
	end
	local fQuery = '( fio_f RLIKE "^' .. table.concat( fPatterns, '$" OR fio_f RLIKE "^' ) .. '$" )' .. ( fExclude or '' )

	local iQuery, oQuery
	if ( i or '' ) ~= '' then
		if string.sub( i, -1, -1 ) == '.' then
			iQuery = 'fio_i LIKE "' .. string.sub( i, 1, -2 ) .. '%"'
		elseif mw.ustring.len( i ) == 1 then
			iQuery = 'fio_i LIKE "' .. i .. '%"'
		else
--			iQuery = 'fio_i IN ( "' .. mw.ustring.sub( i, 1, 1 ) .. '","' .. table.concat( check( i, similarFirst ), '","' ) .. '" )'
			iQuery = 'fio_i IN ( "' .. mw.ustring.sub( i, 1, 1 ) .. '", ' .. ( similarTable.simArray[similarTable.simFirst[i] or 0] or ( '"' .. i .. '"' ) ) .. ' )'
		end
		iQuery = ' AND ( fio_i IS NULL OR ' .. iQuery .. ' )'
	end

	if ( o or '' ) ~= '' then
		if string.sub( o, -1, -1 ) == '.' then
			oQuery = 'fio_o LIKE "' .. string.sub( o, 1, -2 ) .. '%"'
		elseif mw.ustring.len( o ) == 1 then
			oQuery = 'fio_o LIKE "' .. o .. '%"'
		else
			local oo = similarTable.simArray[similarTable.simMiddle[o] or 0]
			if not oo then
				local body = mw.ustring.match( o, '^(.-)[иеь]евич$' )
				if body then
					oo = '"' ..  body .. 'ьевич", "' .. body .. 'иевич", "' .. body .. 'еевич"'
				else
					oo = '"' ..  o .. '"'
				end
			end
			oQuery = 'fio_o IN ( "' .. mw.ustring.sub( o, 1, 1 ) .. '", ' .. oo .. ' )'

		end
		oQuery = ' AND ( fio_o IS NULL OR ' .. oQuery .. ' )'
	end

--	local where = '( fio_f IN ( "' .. table.concat( fAlt, '","' ) .. '" )' .. ( likePart or '' ) .. ' )'
	local where = fQuery
		.. ( iQuery  or '' ).. ( oQuery or '' )
	local res = mw.ext.externalData.getExternalData( { db='cargoview', from = 'aa_szr__names', data = 'fio_f, fio_i, fio_o, fio_d, page, min_date, max_date, counter', where = where, limit = 100 } )
	return res
end


return perstools