841229715e
The file called 274-dev.md was never dev notes — it was the roster. It now sits alongside 274-lookup.csv and 274-lookup.geojson under the same stem, since all three carry the same table. 274-dev.md -> 274-lookup.md the roster, source of truth 274-method.md -> 274-dev.md how it was built References updated: DOC in 274-romaji.py, the roster path in 274-transect-build.py, and the docstrings in both. 274.md now links to the dev notes and the reference tables separately; each of the two docs links to the other and back to the song page. Titles follow: "274 - reference tables" and "274 - how the roster was built". Verified after renaming: 274-romaji.py --check reports no changes and 274-transect-build.py rebuilds 168 entries, so neither script lost its input. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S6MpcBisZYhX45oDGRRJoz
76 lines
3.0 KiB
Python
Executable File
76 lines
3.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Rebuild the data payload inside 274-transect.html from 274-lookup.md.
|
|
|
|
The HTML is self-contained: it carries its data in a <script id="data"> block so
|
|
it opens straight from disk. This script re-reads the roster table out of
|
|
274-lookup.md, joins the route line and district bands, and writes the payload back
|
|
into the HTML in place. The page's markup, CSS and JS are left untouched.
|
|
|
|
python3 274-transect-build.py
|
|
|
|
Inputs : 274-lookup.md (roster, source of truth), 274-route.json, 274-districts.json
|
|
Output : 274-transect.html (data block replaced)
|
|
"""
|
|
import io, json, os, re, sys
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
p = lambda n: os.path.join(HERE, n)
|
|
CHOME = re.compile(r'[一二三四五六七八九十百]+丁目$')
|
|
|
|
|
|
def roster(path):
|
|
hdr, rows = None, []
|
|
for line in io.open(path, encoding='utf-8'):
|
|
if line.startswith('| km | Name |'):
|
|
hdr = [c.strip() for c in line.strip().strip('|').split('|')]
|
|
continue
|
|
if hdr and line.startswith('| ') and line.count('|') >= 13:
|
|
c = [x.strip() for x in line.strip().strip('|').split('|')]
|
|
if re.match(r'^\d+\.\d+$', c[0]):
|
|
rows.append(dict(zip(hdr, c)))
|
|
if not rows:
|
|
sys.exit('no roster rows found in %s' % path)
|
|
return rows
|
|
|
|
|
|
def oaza_of(address, cities):
|
|
a = address or ''
|
|
for c in cities:
|
|
if a.startswith(c):
|
|
a = a[len(c):]
|
|
break
|
|
return CHOME.sub('', a).strip() or '—'
|
|
|
|
|
|
def main():
|
|
bands = json.load(io.open(p('274-districts.json'), encoding='utf-8'))
|
|
route = json.load(io.open(p('274-route.json'), encoding='utf-8'))
|
|
cities = sorted({b['city'] for b in bands if b.get('city')}, key=len, reverse=True)
|
|
|
|
items = []
|
|
for r in roster(p('274-lookup.md')):
|
|
items.append(dict(
|
|
km=float(r['km']), name=r['Name'], obj=r['Object'],
|
|
kana=r.get('Kana', ''), romaji=r.get('Romaji', ''), kind=r['Kind'],
|
|
off=float(r['Off (m)'] or 0), lat=float(r['Lat']), lon=float(r['Lon']),
|
|
L=r.get('Length', ''), y=r.get('Built', ''), g=r.get('Grade', ''),
|
|
addr=r.get('Address', ''), addrk=r.get('Address kana', ''),
|
|
oaza=oaza_of(r.get('Address', ''), cities),
|
|
city=next((c for c in cities if (r.get('Address') or '').startswith(c)), '')))
|
|
items.sort(key=lambda o: (o['km'], o['obj']))
|
|
|
|
payload = json.dumps(dict(route=route, items=items, bands=bands),
|
|
ensure_ascii=False, separators=(',', ':'))
|
|
html = io.open(p('274-transect.html'), encoding='utf-8').read()
|
|
new, n = re.subn(r'(<script id="data" type="application/json">).*?(</script>)',
|
|
lambda m: m.group(1) + payload + m.group(2), html, count=1, flags=re.S)
|
|
if not n:
|
|
sys.exit('data block not found in 274-transect.html')
|
|
io.open(p('274-transect.html'), 'w', encoding='utf-8').write(new)
|
|
print('%d entries, %d district bands, %d route points -> 274-transect.html'
|
|
% (len(items), len(bands), len(route)))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|