Модуль:НОТ Москвы

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
Документация

Модуль для построения списков маршрутов (и остановок маршрутов) наземного общественного транспорта Москвы. Модуль содержит следующие функции:

  • metro_mini — список маршрутов для статьи о станции метро, МЦК или МЦД. Название станции можно передавать как для шаблона {{ММ}}, а можно как название статьи, то есть с последующим уточнением в скобках (за исключением тех станций, для которых шаблон {{ММ}} требует передавать название иначе, чем просто название статьи минус уточнение). Предназначен для карточки статьи.
  • metro_midi — то же, что и metro_mini, но каждый вид транспорта выводится в виде отдельного пункта маркированного списка. Предназначен для тела статьи.
  • metro — то же, что и metro_mini, но с основными остановками для каждого маршрута. По результатам опроса использование этого варианта не поддержано.
  • railway_mini — список маршрутов для статьи о железнодорожной станции, не входящей в МЦД; фильтрация по тегу или линку. Параметр — название статьи о железнодорожной станции. Предназначен для карточки статьи.
  • railway_midi — то же, что и railway_mini, но каждый вид транспорта выводится в виде отдельного пункта маркированного списка. Предназначен для тела статьи.
  • railway — то же, что и metro_mini, но с основными остановками для каждого маршрута. По результатам опроса использование этого варианта не поддержано.
  • num и numfull — один или несколько конкретных маршрутов в том же формате, как metro, с основными и всеми остановками соответственно. Функции поддерживают неограниченный список индексов маршрутов.
  • firstlast — начальная и конечная остановки через тире для заданного маршрута.

Для обращений к модулю создан шаблон {{НОТ Москвы}}.

Примеры вызова функций[править код]

По станциям метро / МЦК / МЦД[править код]

Краткий список маршрутов[править код]

{{#invoke:НОТ Москвы|metro_mini|Бульвар Рокоссовского}}

А: 3, 75, 80, 86, 265, 311, 327, 822; Тм: 4, 7, 13, 36, 46

{{#invoke:НОТ Москвы|metro_mini|Новодачная}}

А: 352, 563, 746

Чуть удлинённый список маршрутов[править код]

{{#invoke:НОТ Москвы|metro_midi|Бульвар Рокоссовского}}

На этой станции можно пересесть на следующие маршруты городского пассажирского транспорта[1]:

{{#invoke:НОТ Москвы|metro_midi|Новодачная}}

На этой станции можно пересесть на следующие маршруты городского пассажирского транспорта[1]:

Полный список маршрутов[править код]

{{#invoke:НОТ Москвы|metro|Бульвар Рокоссовского}}
{{#invoke:НОТ Москвы|metro|Новодачная}}

На этой станции можно пересесть на следующие маршруты городского пассажирского транспорта[1]:

Автобусы
352: Серпуховско-Тимирязевская линия Алтуфьево  ЛианозовоЛианозово Лианозово  Марк Марк  Новодачная  Долгопрудная Долгопрудная
563: Люблинско-Дмитровская линия Верхние Лихоборы  Люблинско-Дмитровская линия Селигерская  Люблинско-Дмитровская линия Яхромская  ЛианозовоЛианозово Лианозово  Марк Марк (→)  Новодачная  Долгопрудная Долгопрудная
746: Северный — 4-й микрорайон  Люблинско-Дмитровская линия Физтех  Новодачная  Долгопрудная Долгопрудная

«→» — остановки проходятся только при движении в прямом направлении; «←» — остановки проходятся только при движении в обратном направлении.


По ж/д станции, не входящей в МЦД[править код]

Краткий список маршрутов[править код]

{{#invoke:НОТ Москвы|railway_mini|Новогиреево (платформа)}}

А: 21, 133, 208, 232, 237, 247, 254, 276, 285, 314, 409, 620, 645, 662, 776, 787, 842, 884, 974, т30, т53, т64, т75, н4; Тм: 36, 37

Чуть удлинённый список маршрутов[править код]

{{#invoke:НОТ Москвы|railway_midi|Новогиреево (платформа)}}

На этой станции можно пересесть на следующие маршруты городского пассажирского транспорта[1]:

Полный список маршрутов[править код]

{{#invoke:НОТ Москвы|railway|Новогиреево (платформа)}}

Конечные пункты по конкретному маршруту[править код]

{{#invoke:НОТ Москвы|firstlast|А м6}}

Стадион «Лужники» (южная)Дангауэровка

Список остановок по конкретным маршрутам[править код]

{{#invoke:НОТ Москвы|num|А м6|А е85|А 123}}
м6: Стадион «Лужники» (южная)  СпортивнаяЛужники Спортивная  Сокольническая линия Кропоткинская  Библиотека имени ЛенинаАрбатскаяАлександровский садБоровицкая Библиотека имени Ленина  Охотный РядТеатральнаяПлощадь Революции Театральная площадь  ЛубянкаКузнецкий Мост Лубянка  Калужско-Рижская линияТаганско-Краснопресненская линия Китай-город  Серп и МолотПлощадь ИльичаРимская Площадь Ильича  Москва-Товарная-Курская Москва-Товарная  АвиамоторнаяАвиамоторная Авиамоторная  Дангауэровка
е85: Каширское шоссе — МКАД  Замоскворецкая линия Домодедовская  Москворечье Москворечье  Замоскворецкая линияБольшая кольцевая линия Каширская  НагатинскаяСерпуховско-Тимирязевская линия Нагатинская  Верхние КотлыМосковское центральное кольцо Верхние Котлы  Серпуховско-Тимирязевская линия Тульская  ДобрынинскаяСерпуховская Добрынинская
123: Серпуховско-Тимирязевская линияЛюблинско-Дмитровская линия Петровско-Разумовская  Московское центральное кольцо Коптево  Замоскворецкая линия Водный стадион

«→» — остановки проходятся только при движении в прямом направлении; «←» — остановки проходятся только при движении в обратном направлении.


Таблицы[править код]

Для полноценного функционирования модуля следует поддерживать в актуальном состоянии три таблицы. Они написаны в формате JSON. Когда требуются комментарии, следует использовать поле "desc". Например,

		{
			"bus": "А 627к",
			"stop": "Амурский переулок",
			"link": "Амурский переулок (Москва)",
			"desc": "временно"
		},

или, чтоб закомментировать элемент целиком,

		{
			"desc": {
				"bus": "А т22",
				"stop": "Комсомольская площадь",
				"m": true
			}
		},

Если выдаётся сообщение, что поле desc уже занято, можно использовать нумерацию, например, desc1, desc2, desc3.

Нет необходимости заботиться о форматировании. Все отступы и переводы строк подставляются движком автоматически, при условии отсутствия сообщений о синтаксических ошибках в редакторе кода.

Таблица complexes (на странице Модуль:НОТ Москвы/data.json)[править код]

Таблица содержит все пересадочные узлы метро, в которых имеются разноимённые станции, а также все случаи, когда несколько разноимённых объектов надо рассматривать как одну остановку. Каждая строка таблицы соответствует одному пересадочному узлу. Все входящие в него несовпадающие названия станций метро заносятся в поля name1, name2, name3, name4, а других объектов — в поля tag1, tag2, tag3, tag4, причём и те, и другие в том же формате, как и в списке остановок (в полях stop/alias и link/tag соответственно).

Таблица buses (на странице Модуль:НОТ Москвы/data.json)[править код]

Таблица содержит все маршруты наземного общественного транспорта. Индекс таблицы состоит из префикса (А, Тб, Тм для автобусов, троллейбусов и трамваев соответственно), пробела и номера маршрута. Поля:

  • kind — А, Тб или Тм;
  • name — номер, можно в виде викиссылки на статью, в которой описывается маршрут;
  • comment (опционально) — примечание, которое должно быть показано в конце списка остановок (скобки и форматирование уменьшенным шрифтом добавляются автоматически);
  • status — два варианта: '+' для временных маршрутов и '-' для временно отменённых;
  • status_from — дата (текстовое поле в формате 'YYYYMMDD'; если она известна), начиная с которой надо показывать временный маршрут либо помечать временно отменённый;
  • status_to — аналогично предыдущему, дата, по которую включительно это надо делать.

Таблица stops (на странице Модуль:НОТ Москвы/stops.json)[править код]

Таблица содержит основные остановки. Порядок перечисления маршрутов и остановок в этой таблице должен соответствовать желаемому порядку их перечисления в статье:

  • bus — маршрут, как в индексе предыдущей таблицы;
  • stop — название остановки;
  • link — название статьи для викификации названия остановки; если совпадает со значением stop, то надо занести значение '=';
  • alias — то же, но для случая, когда остановка называется иначе: тогда в stop задаётся истинное название, а в alias название для поиска;
  • m=true (опционально) — признак, что остановка находится при станции метро/МЦК/МЦД и её название будет пропущено через шаблон {{ММ}}; в противном случае оно будет показано как в поле stop;
  • i=true (опционально) — признак, что остановка является важной; если функция выдаёт не все остановки, то будут выданы только помеченные как i=true и m=true;
  • comment (опционально) — аналогично примечанию в предыдущей таблице, но после конкретной остановки.
  1. 1 2 3 4 5 6 Реестр муниципальных маршрутов регулярных перевозок пассажиров и багажа автомобильным и наземным электрическим транспортом в городе Москве. Портал открытых данных правительства Москвы. Дата обращения: 26 сентября 2020.
local p = {}
local foundcomplex
local greatcomment='<small>«→» — остановки проходятся только при движении в прямом направлении; «←» — остановки проходятся только при движении в обратном направлении.</small>'
local greatfootnote='<ref name="module">{{cite web |author= |url=https://data.mos.ru/opendata/7704786030-reestr-munitsipalnyh-marshrutov-regulyarnyh-perevozok|title=Реестр муниципальных маршрутов регулярных перевозок пассажиров и багажа автомобильным и наземным электрическим транспортом в городе Москве|lang=ru |website=Портал открытых данных правительства Москвы|publisher= |date= |accessdate=2020-09-26}}</ref>'
local zeroedit='[[Категория:Википедия:Страницы с ежедневно совершаемой нулевой правкой]]'

-- Внимание! Данные перенесены в формат JSON, подробности по адресу https://ru.wikipedia.org/wiki/Модуль:НОТ_Москвы#Таблицы (в описании на текущей странице)

-- JSON part
local jsontable = mw.loadJsonData('Модуль:НОТ Москвы/data.json')
local stops = mw.loadJsonData('Модуль:НОТ Москвы/stops.json').stops
function deepcopy(original)
	if (type(original) == 'nil') then
		return nil
	elseif (type(original) == 'number') then
		return 0 + original
	elseif (type(original) == 'string') then
		return '' .. original
	elseif (original == true) then
		return true
	elseif (original == false) then
		return false
	elseif (type(original) == 'function') then
		return mw.clone(original)
	elseif (type(original) ~= 'table') then
		error('Unknown type: ' .. type(original))
	end
	local copy = {}
	for key, value in pairs(original) do
		copy[key] = deepcopy(value)
	end
	return copy
end
local complexes = jsontable.complexes
local kinds = jsontable.kinds
local buses = deepcopy(jsontable.buses)

function p.metro(frame)
	return fu(frame,false,false,false,'На этой станции можно пересесть на следующие маршруты городского пассажирского транспорта'
		..frame:preprocess(greatfootnote)..':')
end
function p.street(frame)
	return fu(frame,true,true,false,'Здесь проходят следующие маршруты городского пассажирского транспорта'
		..frame:preprocess(greatfootnote)..':')
end
function p.railway(frame)
	return fu(frame,true,false,false,'На этой станции можно пересесть на следующие маршруты городского пассажирского транспорта'
		..frame:preprocess(greatfootnote)..':')
end
function p.metro_mini(frame)
	return fu(frame,false,false,true)
end
--function p.street_mini(frame)
--	return fu(frame,true,true,true)
--end
function p.railway_mini(frame)
	return fu(frame,true,false,true)
end
function p.metro_midi(frame)
	return fu(frame,false,false,true,'На этой станции можно пересесть на следующие маршруты городского пассажирского транспорта'
		..frame:preprocess(greatfootnote)..':')
end
function p.railway_midi(frame)
	return fu(frame,true,false,true,'На этой станции можно пересесть на следующие маршруты городского пассажирского транспорта'
		..frame:preprocess(greatfootnote)..':')
end
function p.num(frame)
	return numloop(frame,false)
end
function p.numfull(frame)
	return numloop(frame,true)
end
function numloop(frame,showall)
	local rtn='{|style="line-height:130%; border-collapse:collapse"\r\n'
	local z=false
	for nBus,xBus in pairs(frame.args) do
		if xBus~='' then
			oBus=buses[xBus]
			if bus_ok(oBus) then
				rtn=rtn..onebus(xBus,oBus,'',true,showall,frame,false)
			end
			if zeroedit_needed(oBus) then
				if onebus(xBus,oBus,'',true,showall,frame,true) then
					z=true
				end
			end
		end
	end
	rtn=rtn..'|}\r\n'..greatcomment..'\r\n'
	if z then
		rtn=rtn..zeroedit
	end
	return rtn
end
function p.firstlast(frame)
	local bus=frame.args[1]
	return firstorlast(frame,bus,'both')
end
function firstorlast(frame,bus,what)
	local first=''
	local last=''
	local stop
	for nnStop,xxStop in pairs(stops) do
		if xxStop.bus==bus then
			if what=='both' then
				if xxStop.m then
					stop=frame:expandTemplate{title='Московские маршруты',args={xxStop.stop}}
				else
					stop=xxStop.stop
				end
				if xxStop.link=='=' then
					stop='[['..stop..']]'
				elseif xxStop.link then
					stop='[['..xxStop.link..'|'..stop..']]'
				end
				if xxStop.comment then
					stop=stop..'&nbsp;<small>('..xxStop.comment..')</small>'
				end
			else
				stop=xxStop.stop
			end
			if first=='' then
				if what=='first' then
					return stop
				end	
				first=stop
			end
			last=stop
		end
	end
	if what=='both' then
		return first..' — '..last
	elseif what=='last' then
		return last
	end
end
function fu(frame,bytag,showall,mini,intro)
	local current=frame.args[1]
	local z=false
	if not bytag then
		local pos=string.find(current,'(',1,true)
		if pos then
			current=string.sub(current,1,pos-2)
		end
	end
	local rtnrtn=''
	local cou=0
	for nKind,xKind in pairs(kinds) do
		local rtn=''
		for nStop,xStop in pairs(stops) do
			local oBus=buses[xStop.bus]
			if oBus then
				if oBus.kind==xKind.kind and oBus.done==nil then
					if bus_ok(oBus) then
						local mustdo
						foundcomplex=nil
						for nComplex,xComplex in pairs(complexes) do
							if complex_found(xComplex,current,bytag) then
								foundcomplex=xComplex
							end
						end
						mustdo=stop_ok(xStop,current,bytag,false)
						if mustdo then
							cou=cou+1
							oBus.done=true
							if mini then
								if rtn~='' then
									rtn=rtn..', '
								end
								rtn=rtn..oBus.name
							else
								rtn=rtn..onebus(xStop.bus,oBus,current,bytag,showall,frame,false)
							end
						end
					end
					if zeroedit_needed(oBus) then
						if onebus(xStop.bus,oBus,current,bytag,showall,frame,true) then
							z=true
						end
					end
				end
			end
		end
		if rtn~='' then
			if mini then
				if intro then
					if rtnrtn~='' then
						rtnrtn=rtnrtn..'\r\n'
					end
					rtnrtn=rtnrtn..'* [['..xKind.link..'|'..xKind.title..']]: '..rtn
				else
					if rtnrtn~='' then
						rtnrtn=rtnrtn..'; '
					end
					rtnrtn=rtnrtn..'[['..xKind.link..'|'..xKind.prefix..']]: '..rtn
				end
			else
				rtnrtn=rtnrtn..'|-\r\n!colspan=2 align=left|[['..xKind.link..'|'..xKind.title..']]\r\n'..rtn
			end
		end
	end
	if rtnrtn=='' then
		rtnrtn='[[Категория:Статьи с проблемой в исходных данных в модуле НОТ Москвы]]'
	end
	if mini then
		if z then
			rtnrtn=rtnrtn..zeroedit
		end
		if intro then
			return intro..'\r\n'..rtnrtn
		else
			return rtnrtn
		end
	else
		rtnrtn='{|style="line-height:130%; border-collapse:collapse"\r\n'..rtnrtn..'|}\r\n'..greatcomment..'\r\n'
		if intro then
			rtnrtn=intro..'\r\n'..rtnrtn
		end
		if z then
			rtnrtn=rtnrtn..zeroedit
		end
		if cou>9 then
			return frame:expandTemplate{title='Начало скрытого блока',args={'Список маршрутов'}}..'\r\n'..rtnrtn..'\r\n'..frame:expandTemplate{title='Конец скрытого блока',args={}}
		else
			return rtnrtn
		end
	end
end
function onebus(bus,oBus,current,bytag,showall,frame,for_zeroedit)
	local name=oBus.name
	local tmp=''
	local first=firstorlast(frame,bus,'first')
	local last=firstorlast(frame,bus,'last')
	for nnStop,xxStop in pairs(stops) do
		if xxStop.bus==bus then
			local stop=''
			local isCurrent=stop_ok(xxStop,current,bytag,true)
			if isCurrent then
				if for_zeroedit then
					return true
				end
				stop=xxStop.stop
			elseif xxStop.m then
				stop=frame:expandTemplate{title='Московские маршруты',args={xxStop.stop}}
			elseif xxStop.i or showall or xxStop.stop==first or xxStop.stop==last then
				stop=xxStop.stop
			end
			if stop~='' then
				if tmp~='' then
					tmp=tmp..'&nbsp;<b>•</b> '
				end
				local i1=''
				local i2=''
				if stop_ok(xxStop,current,bytag,false) then
					i1='<i>'
					i2='</i>'
				end
				if isCurrent then
					tmp=tmp..i1..stop..i2
				elseif xxStop.link then
					if xxStop.link=='=' then
						tmp=tmp..i1..'[['..stop..']]'..i2
					else
						tmp=tmp..i1..'[['..xxStop.link..'|'..stop..']]'..i2
					end
				else
					tmp=tmp..i1..stop..i2
				end
				if xxStop.comment then
					tmp=tmp..'&nbsp;<small>('..xxStop.comment..')</small>'
				end
			end
		end
	end
	if for_zeroedit then
		return false
	end
	if oBus.comment then
		tmp=tmp..' <small>('..oBus.comment..')</small>'
	end
	if oBus.status=='+' then
		name=name..' <small>(временно введён)</small>'
	elseif oBus.status=='-' and status_ok(oBus) then
		name=name..' <small>(временно отменён)</small>'
	end
	return '|-\r\n!style="vertical-align:top; text-align:right; width:2.5em" nowrap|'..name..':\r\n|'..tmp..'\r\n'
end
function status_ok(oBus)
	local today=os.date('%Y%m%d')
	if oBus.status_from then
		if today<oBus.status_from then
			return false
		end
	end
	if oBus.status_to then
		if today>oBus.status_to then
			return false
		end
	end
	return true
end
function zeroedit_needed(oBus)
	return oBus.status_from~=nil or oBus.status_to~=nil
end
function bus_ok(oBus)
	if oBus.status=='+' and not status_ok(oBus) then
		return false
	elseif oBus.status=='-' and status_ok(oBus) then
		return false
	else
		return true
	end
end
function stop_ok(oStop,current,bytag,forlink)
	if oStop.m then
		cf=complex_found(foundcomplex,oStop.stop,false) or complex_found(foundcomplex,oStop.alias,false)
	else
		cf=complex_found(foundcomplex,oStop.tag,true) or complex_found(foundcomplex,oStop.tag2,true)
			or complex_found(foundcomplex,oStop.link,true) or (oStop.link=='=' and  complex_found(foundcomplex,oStop.stop,true))
	end
	if bytag then
		return ((oStop.tag==current or oStop.tag2==current) and not forlink) or oStop.link==current or (oStop.link=='=' and oStop.stop==current)
			or cf
	else
		return oStop.m==true and (oStop.stop==current or oStop.alias==current) or cf
	end
end
function complex_found(oComplex,cur,bytag)
	if cur==nil or oComplex==nil then
		return false
	end
	if bytag then
		return cur==oComplex.tag1 or cur==oComplex.tag2 or cur==oComplex.tag3 or cur==oComplex.tag4
	else
		return cur==oComplex.name1 or cur==oComplex.name2 or cur==oComplex.name3 or cur==oComplex.name4
	end
end
return p
-- =p.list{args={'Боровицкая'}}