clean up and refactor half-baked development commits and squash them into a new version.

Changes:

* support for multiple GTFS feeds as input in filtering, read default global and local configuration files
* be a bit more memory conservative
* make caching optional
* dont delete orphan edge if it would transform a degree 3 node with a possible full turn into a degree 2 node eligible for contraction
* dedicated filters for funicular and gondola
* make max snap level option more intuitive
* allow filter rules for level 0
* additional fallback for station snapping
* dont try to route for MOT unequal to trip in -T mode, force-snap to orphaned OSM station if not snap was possible
* write bounds to filtered osm
* remove unused surrounding heuristic
* use bus lanes info
* be a bit more tolerant for bus oneway streets
* create missing directories
* error if no cfg is present, clean up evaluation Makefile
This commit is contained in:
Patrick Brosi 2019-01-10 16:52:59 +01:00
parent 2cc2d2dc23
commit 63f0b61ea1
60 changed files with 4532 additions and 1576 deletions

View file

@ -2,6 +2,216 @@
# Chair of Algorithms and Datastructures
# Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
[tram, bus, coach, subway, rail, gondola, funicular, ferry]
# Regular expressions and station comparision is
# always case insensitive!
station_normalize_chain:
, -> ' ';
- -> ' ';
— -> ' ';
_ -> ' ';
" -> '';
' -> '';
` -> '';
\( -> ' ';
\) -> ' ';
\[ -> ' ';
\] -> ' ';
/ -> ' ';
'\\' -> ' ';
< -> ' ';
> -> ' ';
& -> '+';
Ä -> Ae;
Ö -> Oe;
Ü -> Ue;
ä -> ae;
ö -> oe;
ü -> ue;
ß -> ss;
è -> e;
é -> e;
á -> a;
à -> a;
ó -> o;
ò -> o;
ô -> o;
ç -> c;
í -> i;
ú -> u;
ù -> u;
ë -> e;
å -> ae;
â -> a;
ê -> e;
ï -> i;
œ -> oe;
ø -> oe;
str\. -> strasse;
av\. -> avenue;
# always separate 'street', 'strasse'
'([a-zA-Z])strasse($| )' -> '\1 strasse\2';
'([a-zA-Z])street($| )' -> '\1 street\2';
# always use "street"
'(^| )strasse($| )' -> '\1street\2';
# always use "avenue"
'(^| )avenida($| )' -> '\1avenue\2';
'(^| )avenu($| )' -> '\1avenue\2';
# normalize every possible abbr. of german "Bahnhof", "Hauptbahnhof", "Busbahnhof"
'(^| )hauptbf\.($| )' -> '\1hauptbahnhof\2';
'(^| )hauptbf($| )' -> '\1hauptbahnhof\2';
'(^| )hauptbhf\.($| )' -> '\1hauptbahnhof\2';
'(^| )hauptbhf($| )' -> '\1hauptbahnhof\2';
'(^| )zentraler busbahnhof($| )$' -> \1busbahnhof\2;
'(^| )zentraler omnibusbahnhof($| )$' -> \1busbahnhof\2;
'(^| )omnibusbahnhof($| )' -> '\1busbahnhof\2';
'(^| )omnibusbhf($| )' -> '\1busbahnhof\2';
'(^| )busbf\.($| )' -> '\1busbahnhof\2';
'(^| )busbf($| )' -> '\1busbahnhof\2';
'(^| )bus bf\.($| )' -> '\1busbahnhof\2';
'(^| )bus bf($| )' -> '\1busbahnhof\2';
'(^| )busbhf\.($| )' -> '\1busbahnhof\2';
'(^| )busbhf($| )' -> '\1busbahnhof\2';
'(^| )bus bhf\.($| )' -> '\1busbahnhof\2';
'(^| )bus bhf($| )' -> '\1busbahnhof\2';
'(^| )zob($| )' -> '\1busbahnhof\2';
'(^| )hbf\.($| )' -> '\1hauptbahnhof\2';
'(^| )hbf($| )' -> '\1hauptbahnhof\2';
'(^| )hb\.($| )' -> '\1hauptbahnhof\2';
'(^| )hb($| )' -> '\1hauptbahnhof\2';
'(^| )bf\.($| )' -> '\1bahnhof\2';
'(^| )bf($| )' -> '\1bahnhof\2';
'(^| )bhf\.($| )' -> '\1bahnhof\2';
'(^| )bhf($| )' -> '\1bahnhof\2';
'(^| )bhfeingang($| )' -> '\1bahnhofeingang\2';
'(^| )gare de($| )' -> '\1gare\2';
# if a stations starts with single station identifier
# always put it at the end (for example, "hauptbahnhof freiburg" becomes "freiburg hauptbahnhof")
'^hauptbahnhof (.+)$' -> \1 hauptbahnhof;
'^bahnhof (.+)$' -> \1 bahnhof;
'^busbahnhof (.+)$' -> \1 busbahnhof;
'^gare (.+)$' -> \1 gare;
'^station (.+)$' -> \1 station;
'(^| )busbahnhof($| )' -> '\1bbahnhof\2';
# normalize line types in station names
'(^| )u bahn\.($| )' -> '\1ubahn\2';
'(^| )metro\.($| )' -> '\1ubahn\2';
'(^| )subway\.($| )' -> '\1ubahn\2';
'(^| )underground\.($| )' -> '\1ubahn\2';
'(^| )ubahn($| )' -> '\1u\2';
'(^| )s bahn\.($| )' -> '\1sbahn\2';
'(^| )sbahn($| )' -> '\1s\2';
'(^| )tramway($| )' -> '\1tram\2';
'(^| )stadtbahn($| )' -> '\1tram\2';
'(^| )strassenbahn($| )' -> '\1tram\2';
'(^| )streetcar($| )' -> '\1tram\2';
'(^| )tram($| )' -> '\1t\2';
# delete track information from name
'(^| )kante [a-zA-Z0-9]{1,2}($| )' -> ' ';
'(^| )gleis [a-zA-Z0-9]{1,2}($| )' -> ' ';
'(^| )track [a-zA-Z0-9]{1,2}($| )' -> ' ';
'(^| )voie [a-zA-Z0-9]{1,2}($| )' -> ' ';
# abbrv
'(^| )und($| )' -> '\1+\2';
'(^| )and($| )' -> '\1+\2';
'(^| )et($| )' -> '\1+\2';
# noise
'\sde\s' -> ' ';
'\sda\s' -> ' ';
'\sdi\s' -> ' ';
'\sdel\s' -> ' ';
'\sdal\s' -> ' ';
# abbrv in most western languages
'(^| )saint ' -> '\1st. ';
'(^| )sankt ' -> '\1st. ';
'(^| )sanct ' -> '\1st. ';
\. -> ' ';
# whitespace
\s+ -> ' ';
^\s -> '';
\s$ -> '';
line_normalize_chain:
, -> ' ';
- -> ' ';
_ -> ' ';
" -> '';
' -> '';
` -> '';
/ -> ' ';
< -> ' ';
> -> ' ';
& -> '+';
ä -> ae;
ö -> oe;
ü -> ue;
Ä -> Ae;
Ö -> Oe;
Ü -> Ue;
ß -> ss;
è -> e;
é -> e;
á -> a;
à -> a;
ó -> o;
ò -> o;
í -> i;
ú -> u;
ù -> u;
ë -> e;
å -> ae;
ç -> c;
â -> a;
ê -> e;
ï -> i;
œ -> oe;
ø -> oe;
^line -> '';
^linie -> '';
^metro -> '';
^tram -> '';
^strassenbahn -> '';
^bus -> '';
# delete everything in brackets
\(.+\) -> ' ';
\[.+\] -> ' ';
# whitespace
\s+ -> ' ';
^\s -> '';
\s$ -> '';
# line/number combs ALWAYS without whitespace (T 2 -> T2)
^([a-zA-Z]+) ([0-9]+)$ -> \1\2;
track_normalize_chain:
'(^| )gleis($| )' -> '';
'(^| )gl\.($| )' -> '';
'(^| )platform($| )' -> '';
'(^| )track($| )' -> '';
'(^| )rail($| )' -> '';
# line/number combs ALWAYS without whitespace (1 A -> 1A)
^([a-zA-Z]+) ([0-9]+)$ -> \1\2;
^([0-9]+) ([a-zA-Z]+)$ -> \1\2;
# delete track numbers greater than 999
^[0-9]{4,}$ -> '';
[rail]
# OSM entities to keep on different levels, as k=v. Applies
@ -12,8 +222,10 @@
osm_filter_keep:
railway=rail
railway=light_rail
railway=tram
railway=narrow_gauge
route=rail
route=light_rail
route=train
public_transport=stop_area|rel_flat
@ -21,10 +233,11 @@ osm_filter_lvl1:
usage=branch
osm_filter_lvl2:
railway=tram
service=siding
osm_filter_lvl3:
service=crossover
service=siding
# we cannot completely drop service=yard, because it is often used
# incorrectly for crossovers
service=yard
@ -213,6 +426,9 @@ line_normalize_chain:
ä -> ae;
ö -> oe;
ü -> ue;
Ä -> Ae;
Ö -> Oe;
Ü -> Ue;
ß -> ss;
è -> e;
é -> e;
@ -253,7 +469,21 @@ line_normalize_chain:
# if a character line number is present, delete the numeric part
^([a-zA-Z]+) [0-9]+$ -> \1;
[bus]
track_normalize_chain:
'(^| )gleis($| )' -> '';
'(^| )gl\.($| )' -> '';
'(^| )platform($| )' -> '';
'(^| )track($| )' -> '';
'(^| )rail($| )' -> '';
^([a-zA-Z]+) ([0-9]+)$ -> \1\2;
# number/char combs ALWAYS without char
^([0-9]+) ([a-zA-Z]+)$ -> \1;
^([0-9]+)([a-zA-Z]+)$ -> \1;
# delete track numbers greater than 999
^[0-9]{4,}$ -> '';
[bus, coach]
# OSM entities to keep on different levels, as k=v. Applies
# to nodes, edges and relations.
@ -287,6 +517,18 @@ osm_filter_keep:
psv=yes
psv=designated
bus:lanes=yes
bus:lanes=designated
bus:lanes=1
lanes:bus=1
lanes:bus=2
lanes:bus=3
lanes:psv=1
lanes:psv=2
lanes:psv=3
trolley_wire=yes
trolleywire=yes
trolleybus=yes
@ -448,6 +690,14 @@ osm_filter_undirected:
busway:right=opposite_lane
psv=opposite_lane
psv=opposite
lanes:psv:backward=1
lanes:psv:backward=2
lanes:bus:backward=1
lanes:bus:backward=2
bus:lanes:backward=yes
bus:lanes:backward=designated
bus:lanes:backward=1
# Nodes that are stations.
# Only nodes that have been kept during the filtering above will be
@ -486,11 +736,13 @@ osm_station_group_attrs:
# max distance in meters between a snapped station position and the
# original station position
osm_max_snap_distance: 10 , 50, 100
osm_max_snap_distance: 10, 50, 100
osm_max_snap_fallback_distance: 300
osm_max_snap_level: 5
osm_max_osm_station_distance: 7.5
osm_max_osm_station_distance: 8.0
# sorted by priority, first found attr will be taken
osm_station_name_attrs:
@ -541,7 +793,65 @@ routing_one_way_edge_punish: 5000
# information
# routing_line_unmatched_punish_fac: 1.75
[tram, subway, funicular]
[coach]
# OSM entities to keep on different levels, as k=v. Applies
# to nodes, edges and relations.
# Nodes included in kept ways are always kept.
# Ways included in kept relations are always kept.
osm_filter_lvl0:
highway=motorway
highway=motorway_link
osm_filter_lvl1:
highway=trunk
highway=trunk_link
osm_filter_lvl2:
highway=primary
highway=primary_link
osm_filter_lvl3:
highway=secondary
highway=secondary_link
osm_filter_lvl4:
highway=tertiary
highway=tertiary_link
osm_filter_lvl5:
highway=unclassified
highway=residential
highway=road
highway=service
osm_filter_lvl6:
highway=living_street
highway=pedestrian
psv=no
osm_filter_lvl7:
bus=no
service=siding
access=permissive
access=private
access=no
service=parking_aisle
highway=footway
routing_lvl0_fac: 1 # default level
routing_lvl1_fac: 1.15
routing_lvl2_fac: 1.5
routing_lvl3_fac: 1.75
routing_lvl4_fac: 2.25
routing_lvl5_fac: 2.5
routing_lvl6_fac: 3
routing_lvl7_fac: 4
osm_max_snap_level: 5
[tram, subway]
# OSM entities to keep on different levels, as k=v. Applies
# to nodes, edges and relations.
@ -550,6 +860,7 @@ routing_one_way_edge_punish: 5000
osm_filter_keep:
route=tram
route=funicular
railway=subway
railway=light_rail
railway=tram
@ -562,9 +873,326 @@ osm_filter_keep:
subway=yes
tram=yes
osm_filter_lv2:
osm_filter_lvl2:
service=siding
osm_filter_lvl3:
railway=funicular
route=funicular
osm_filter_lvl5:
service=crossover
service=yard
# OSM entities to drop, as k=v. Applies to nodes, edges and
# relations.
# Nodes included in non-dropped ways are kept regardless of
# a matching drop filter.
# Ways included in non-dropped relations are kept regardless of
# a matching drop filter.
osm_filter_drop:
area=yes
public_transport=stop_area
type=multipolygon
railway=platform
public_transport=platform
service=alley
# Nodes that should act as "no-hup" nodes. These are nodes
# that are contained in multiple ways, but cannot be used
# to switch from one way to another (for example, a
# track crossing in rail networks)
osm_filter_nohup:
railway:switch=no
railway=railway_crossing
# Edges that should act as one-way nodes.
osm_filter_oneway:
oneway=yes
# Edges that may explicitely be used in
# both directions. May be used to set exception
# to "osm_filter_oneway"
osm_filter_undirected:
# Nodes that are stations.
# Only nodes that have been kept during the filtering above will be
# checked.
osm_filter_station:
public_transport=stop_position
station=subway
station=tram
railway=stop
railway=halt
railway=station
railway=tram_stop
railway=subway_stop
tram_stop=*
stop=*
# Relation fields that should be used for catching the lines that
# occur on an edge. Only relations that have been kept during the
# filtering above will be checked. The 'linename' will be normalized
# according to the rules in line_normalization_chain.
# The 'from_name' and 'to_name' will be normalized according to the
# rules in station_normalization_chain.
# The relations tags are given in the order of their relevance -
# the first normalized tag-value that is not null/empty will be
# taken.
osm_line_relation_tags:
line_name=ref,name # careful, no space after/before comma allowed!
from_name=from
to_name=to
# attr name together with the
# max distance in meters between any of the groups members and
# a potential new member
# first matching rule will be taken
# only applies to nodes that match osm_filter_station!
osm_station_group_attrs:
uic_ref=500
wikidata=500
name=100
# max distance in meters between a snapped station position and the
# original station position
osm_max_snap_distance: 10, 50, 100
osm_max_snap_level: 4
# sorted by priority, first found attr will be taken
osm_station_name_attrs:
name
uic_name
# the track number tag in stop nodes, first one is taken
osm_track_number_tags: local_ref
routing_lvl0_fac: 1 # default level
routing_lvl1_fac: 1.5
routing_lvl2_fac: 2
routing_lvl3_fac: 2.5
routing_lvl4_fac: 3.5
routing_lvl5_fac: 5
routing_lvl6_fac: 5
routing_lvl7_fac: 5
# Punishment (in meters) to add to the distance
# function if a vehicle performans a full turn
routing_full_turn_punish: 2000
routing_station_distance_punish_fac: 3.14
routing_non_osm_station_punish: 235
# Max angle that should be counted as a full turn
routing_full_turn_angle: 80
# Max angle in a route from a station to an already reachable neighbar
routing_snap_full_turn_angle: 80
# Punishment (in meters) to add to the distance
# function if a vehicle passes a station node without
# stopping there
routing_pass_thru_station_punish: 100
# Punishment factor for every meter a vehicle
# travels through a one-way edge
routing_one_way_meter_punish_fac: 1
# Punishment factor for every meter a vehicle
# travels through an edge without any matching line
# information
routing_line_unmatched_punish_fac: 0.5
[gondola]
# OSM entities to keep on different levels, as k=v. Applies
# to nodes, edges and relations.
# Nodes included in kept ways are always kept.
# Ways included in kept relations are always kept.
osm_filter_keep:
aerialway=gondola
aerialway=cable_car
aerialway=chair_lift
aerialway=mixed_lift
# OSM entities to drop, as k=v. Applies to nodes, edges and
# relations.
# Nodes included in non-dropped ways are kept regardless of
# a matching drop filter.
# Ways included in non-dropped relations are kept regardless of
# a matching drop filter.
osm_filter_drop:
area=yes
public_transport=stop_area
type=multipolygon
railway=platform
public_transport=platform
service=alley
# Nodes that should act as "no-hup" nodes. These are nodes
# that are contained in multiple ways, but cannot be used
# to switch from one way to another (for example, a
# track crossing in rail networks)
osm_filter_nohup:
# Edges that should act as one-way nodes.
osm_filter_oneway:
oneway=yes
# Edges that may explicitely be used in
# both directions. May be used to set exception
# to "osm_filter_oneway"
osm_filter_undirected:
# Nodes that are stations.
# Only nodes that have been kept during the filtering above will be
# checked.
osm_filter_station:
aerialway=station
aerialway=stop
public_transport=stop_position
station=subway
station=tram
railway=stop
railway=halt
railway=station
railway=tram_stop
railway=subway_stop
tram_stop=*
stop=*
# Relation fields that should be used for catching the lines that
# occur on an edge. Only relations that have been kept during the
# filtering above will be checked. The 'linename' will be normalized
# according to the rules in line_normalization_chain.
# The 'from_name' and 'to_name' will be normalized according to the
# rules in station_normalization_chain.
# The relations tags are given in the order of their relevance -
# the first normalized tag-value that is not null/empty will be
# taken.
osm_line_relation_tags:
line_name=ref,name # careful, no space after/before comma allowed!
from_name=from
to_name=to
# attr name together with the
# max distance in meters between any of the groups members and
# a potential new member
# first matching rule will be taken
# only applies to nodes that match osm_filter_station!
osm_station_group_attrs:
uic_ref=500
wikidata=500
name=100
# max distance in meters between a snapped station position and the
# original station position
osm_max_snap_distance: 10, 50, 100
osm_max_snap_level: 4
# sorted by priority, first found attr will be taken
osm_station_name_attrs:
name
uic_name
# the track number tag in stop nodes, first one is taken
osm_track_number_tags: local_ref
routing_lvl0_fac: 1 # default level
routing_lvl1_fac: 1.5
routing_lvl2_fac: 2
routing_lvl3_fac: 2.5
routing_lvl4_fac: 3.5
routing_lvl5_fac: 5
routing_lvl6_fac: 5
routing_lvl7_fac: 5
# Punishment (in meters) to add to the distance
# function if a vehicle performans a full turn
routing_full_turn_punish: 2000
routing_station_distance_punish_fac: 3.14
routing_non_osm_station_punish: 235
# Max angle that should be counted as a full turn
routing_full_turn_angle: 80
# Max angle in a route from a station to an already reachable neighbar
routing_snap_full_turn_angle: 80
# Punishment (in meters) to add to the distance
# function if a vehicle passes a station node without
# stopping there
routing_pass_thru_station_punish: 100
# Punishment factor for every meter a vehicle
# travels through a one-way edge
routing_one_way_meter_punish_fac: 1
# Punishment factor for every meter a vehicle
# travels through an edge without any matching line
# information
routing_line_unmatched_punish_fac: 0.5
[funicular]
# OSM entities to keep on different levels, as k=v. Applies
# to nodes, edges and relations.
# Nodes included in kept ways are always kept.
# Ways included in kept relations are always kept.
osm_filter_keep:
route=funicular
railway=funicular
railway=narrow_gauge
route=tram
railway=subway
railway=light_rail
railway=tram
railway=station
railway=halt
railway=tram_stop
route=subway
route=light_rail
subway=yes
tram=yes
osm_filter_lvl2:
service=siding
osm_filter_lvl3:
route=tram
route=narrow_gauge
railway=subway
railway=narrow_gauge
railway=light_rail
railway=tram
railway=station
railway=halt
railway=tram_stop
route=subway
route=light_rail
subway=yes
tram=yes
osm_filter_lvl5:
service=crossover
service=yard
@ -797,206 +1425,3 @@ routing_one_way_meter_punish_fac: 1
# information
routing_line_unmatched_punish_fac: 0.5
[tram, bus, subway, rail, gondola, funicular, ferry]
# Regular expressions and station comparision is
# always case insensitive!
station_normalize_chain:
, -> ' ';
- -> ' ';
— -> ' ';
_ -> ' ';
" -> '';
' -> '';
` -> '';
\( -> ' ';
\) -> ' ';
\[ -> ' ';
\] -> ' ';
/ -> ' ';
'\\' -> ' ';
< -> ' ';
> -> ' ';
& -> '+';
ä -> ae;
ö -> oe;
ü -> ue;
ß -> ss;
è -> e;
é -> e;
á -> a;
à -> a;
ó -> o;
ò -> o;
ô -> o;
ç -> c;
í -> i;
ú -> u;
ù -> u;
ë -> e;
å -> ae;
â -> a;
ê -> e;
ï -> i;
œ -> oe;
ø -> oe;
str\. -> strasse;
av\. -> avenue;
# always separate 'street', 'strasse'
'([a-zA-Z])strasse($| )' -> '\1 strasse\2';
'([a-zA-Z])street($| )' -> '\1 street\2';
# always use "street"
'(^| )strasse($| )' -> '\1street\2';
# always use "avenue"
'(^| )avenida($| )' -> '\1avenue\2';
'(^| )avenu($| )' -> '\1avenue\2';
# normalize every possible abbr. of german "Bahnhof", "Hauptbahnhof", "Busbahnhof"
'(^| )hauptbf\.($| )' -> '\1hauptbahnhof\2';
'(^| )hauptbf($| )' -> '\1hauptbahnhof\2';
'(^| )hauptbhf\.($| )' -> '\1hauptbahnhof\2';
'(^| )hauptbhf($| )' -> '\1hauptbahnhof\2';
'(^| )zentraler busbahnhof($| )$' -> \1busbahnhof\2;
'(^| )zentraler omnibusbahnhof($| )$' -> \1busbahnhof\2;
'(^| )omnibusbahnhof($| )' -> '\1busbahnhof\2';
'(^| )omnibusbhf($| )' -> '\1busbahnhof\2';
'(^| )busbf\.($| )' -> '\1busbahnhof\2';
'(^| )busbf($| )' -> '\1busbahnhof\2';
'(^| )bus bf\.($| )' -> '\1busbahnhof\2';
'(^| )bus bf($| )' -> '\1busbahnhof\2';
'(^| )busbhf\.($| )' -> '\1busbahnhof\2';
'(^| )busbhf($| )' -> '\1busbahnhof\2';
'(^| )bus bhf\.($| )' -> '\1busbahnhof\2';
'(^| )bus bhf($| )' -> '\1busbahnhof\2';
'(^| )zob($| )' -> '\1busbahnhof\2';
'(^| )hbf\.($| )' -> '\1hauptbahnhof\2';
'(^| )hbf($| )' -> '\1hauptbahnhof\2';
'(^| )hb\.($| )' -> '\1hauptbahnhof\2';
'(^| )hb($| )' -> '\1hauptbahnhof\2';
'(^| )bf\.($| )' -> '\1bahnhof\2';
'(^| )bf($| )' -> '\1bahnhof\2';
'(^| )bhf\.($| )' -> '\1bahnhof\2';
'(^| )bhf($| )' -> '\1bahnhof\2';
'(^| )bhfeingang($| )' -> '\1bahnhofeingang\2';
'(^| )gare de($| )' -> '\1gare\2';
# if a stations starts with single station identifier
# always put it at the end (for example, "hauptbahnhof freiburg" becomes "freiburg hauptbahnhof")
'^hauptbahnhof (.+)$' -> \1 hauptbahnhof;
'^bahnhof (.+)$' -> \1 bahnhof;
'^busbahnhof (.+)$' -> \1 busbahnhof;
'^gare (.+)$' -> \1 gare;
'^station (.+)$' -> \1 station;
'(^| )busbahnhof($| )' -> '\1bbahnhof\2';
# normalize line types in station names
'(^| )u bahn\.($| )' -> '\1ubahn\2';
'(^| )metro\.($| )' -> '\1ubahn\2';
'(^| )subway\.($| )' -> '\1ubahn\2';
'(^| )underground\.($| )' -> '\1ubahn\2';
'(^| )ubahn($| )' -> '\1u\2';
'(^| )s bahn\.($| )' -> '\1sbahn\2';
'(^| )sbahn($| )' -> '\1s\2';
'(^| )tramway($| )' -> '\1tram\2';
'(^| )stadtbahn($| )' -> '\1tram\2';
'(^| )strassenbahn($| )' -> '\1tram\2';
'(^| )streetcar($| )' -> '\1tram\2';
'(^| )tram($| )' -> '\1t\2';
# delete track information from name
'(^| )kante [a-zA-Z0-9]{1,2}($| )' -> ' ';
'(^| )gleis [a-zA-Z0-9]{1,2}($| )' -> ' ';
'(^| )track [a-zA-Z0-9]{1,2}($| )' -> ' ';
'(^| )voie [a-zA-Z0-9]{1,2}($| )' -> ' ';
# abbrv
'(^| )und($| )' -> '\1+\2';
'(^| )and($| )' -> '\1+\2';
'(^| )et($| )' -> '\1+\2';
# noise
'\sde\s' -> ' ';
'\sda\s' -> ' ';
'\sdi\s' -> ' ';
'\sdel\s' -> ' ';
'\sdal\s' -> ' ';
# abbrv in most western languages
'(^| )saint ' -> '\1st. ';
'(^| )sankt ' -> '\1st. ';
'(^| )sanct ' -> '\1st. ';
\. -> ' ';
# whitespace
\s+ -> ' ';
^\s -> '';
\s$ -> '';
line_normalize_chain:
, -> ' ';
- -> ' ';
_ -> ' ';
" -> '';
' -> '';
` -> '';
/ -> ' ';
< -> ' ';
> -> ' ';
& -> '+';
ä -> ae;
ö -> oe;
ü -> ue;
ß -> ss;
è -> e;
é -> e;
á -> a;
à -> a;
ó -> o;
ò -> o;
í -> i;
ú -> u;
ù -> u;
ë -> e;
å -> ae;
ç -> c;
â -> a;
ê -> e;
ï -> i;
œ -> oe;
ø -> oe;
^line -> '';
^linie -> '';
^metro -> '';
^tram -> '';
^strassenbahn -> '';
^bus -> '';
# delete everything in brackets
\(.+\) -> ' ';
\[.+\] -> ' ';
# whitespace
\s+ -> ' ';
^\s -> '';
\s$ -> '';
# line/number combs ALWAYS without whitespace (T 2 -> T2)
^([a-zA-Z]+) ([0-9]+)$ -> \1\2;
track_normalize_chain:
'(^| )gleis($| )' -> '';
'(^| )gl\.($| )' -> '';
'(^| )platform($| )' -> '';
'(^| )track($| )' -> '';
'(^| )rail($| )' -> '';
# line/number combs ALWAYS without whitespace (1 A -> 1A)
^([a-zA-Z]+) ([0-9]+)$ -> \1\2;
^([0-9]+) ([a-zA-Z]+)$ -> \1\2;
# delete track numbers greater than 999
^[0-9]{4,}$ -> '';