perl + .osm

Во! Спасибо, работает!

А то я чота типа такого намалевал: $rawtext =~ s/.[[cs:(\w+)]]./\1/s;

Разные вариации либо весь текст оставляют, либо от нужного места до конца, либо вообще всё съедается. :slight_smile:

Так, теперь у меня есть осм-файл с более 600 чешских городов, плюс список соответствия чешских и русских названий чуть более сотни городов, взятый из википедии:


Прага:Praha
Брно:Brno
Острава:Ostrava
Пльзень:Plzeň
Либерец:Liberec
Оломоуц:Olomouc
Усти-над-Лабем:Ústí nad Labem
Градец-Кралове:Hradec Králové
Ческе-Будеёвице:České Budějovice
Пардубице:Pardubice
Гавиржов:Havířov
Злин:Zlín
Кладно:Kladno
Мост (город):
Карвина:Karviná
Фридек-Мистек:Frýdek-Místek
Опава:Opava
Карлови-Вари:
Теплице:Teplice
Дечин:Děčín
Йиглава:Jihlava
Хомутов (город):
Пршеров:Přerov
Яблонец-над-Нисоу:Jablonec nad Nisou
Простеёв:Prostějov
Млада-Болеслав:Mladá Boleslav
Ческа-Липа:Česká Lípa
Тршебич:Třebíč
Тршинец:Třinec
Табор (город):Tábor
Абертамы:
Адамов (район Бланско):Adamov (okres Blansko)
Аш:Aš
Бенешов:Benešov
Бероун:Beroun
Брно:Brno
Всетин:Vsetín
Вишков:Vyškov
Гавиржов:Havířov
Гавличкув-Брод:Havlíčkův Brod
Глучин:Hlučín
Годонин:Hodonín
Градец-Кралове:Hradec Králové
Двур-Кралове:
Дечин:Děčín
Дивишов:Divišov
Домажлице:Domažlice
Есеник:Jeseník
Жатец:Žatec
Железна-Руда:Železná Ruda
Злин:Zlín
Зноймо:Znojmo
Йиглава:Jihlava
Йиндржихув-Градец:Jindřichův Hradec
Йичин:Jičín
Карвина:Karviná
Карловы Вары:Karlovy Vary
Кашперске-Гори:Kašperské Hory
Кинжварт:
Кладно:Kladno
Клатови:Klatovy
Колин:Kolín
Коуржим:Kouřim
Кралупи:
Крнов:Krnov
Кутна-Гора:Kutná Hora
Лазне-Богданеч:Lázně Bohdaneč
Ланшкроун:Lanškroun
Летоград:Letohrad
Либерец:Liberec
Либице:
Литомержице:Litoměřice
Литомышль:
Лоуни:Louny
Лугачовице:Luhačovice
Марианске-Лазне:Mariánské Lázně
Мельник (город):Mělník
Миловице:Milovice
Мирослав (город):Miroslav (okres Znojmo)
Млада-Болеслав:Mladá Boleslav
Мнихово-Градиште:Mnichovo Hradiště
Мост (город):
Мшено:Mšeno
Нимбурк:Nymburk
Нови-Йичин:Nový Jičín
Оломоуц:Olomouc
Опава:Opava
Острава:Ostrava
Пардубице:Pardubice
Писек:Písek (město)
Пльзень:Plzeň
Подебради:Poděbrady
Прага:Praha
Пршебуз:Přebuz
Пршибислав:Přibyslav
Пршибор:Příbor (okres Nový Jičín)
Пршибрам:Příbram
Рожмберк-над-Влтавоу:Rožmberk nad Vltavou
Раковник:Rakovník
Рокицани:Rokycany
Роуднице-над-Лабем:Roudnice nad Labem
Свитави:Svitavy
Седлец-Прчице:Sedlec-Prčice
Славков-у-Брна:Slavkov u Brna
Соколов (город):
Страконице:Strakonice
Табор (город):Tábor
Тахов:Tachov
Телч:
Теплице:Teplice
Терезин:Terezín
Трутнов:Trutnov
Тршебич:Třebíč
Тршебонь:Třeboň
Тршинец:Třinec
Усти-над-Лабем:Ústí nad Labem
Усти-над-Орлици:Ústí nad Orlicí
Франтишкови-Лазне:Františkovy Lázně
Фридек-Мистек:Frýdek-Místek
Фридлант:Frýdlant
Фульнек:Fulnek
Хеб:Cheb
Хомутов (город):
Хрудим:Chrudim
Ческа Липа:
Ческе-Будеёвице:České Budějovice
Чески-Крумлов:Český Krumlov
Чески-Тешин:Český Těšín
Шлукнов:Šluknov
Шумперк:Šumperk
Яблонец-над-Нисоу:Jablonec nad Nisou

Как теперь это всё залить в name:ru ?

Что-то типа

use Geo::Parse::OSM;

my $addname = sub {
    if ( ... ) {
        $_[0]->{action} = 'modify';
        $_[0]->{tag}->{'name:ru'} = ...;
        print Geo::Parse::OSM->to_xml( $_[0] );
    } 
};

print "<osm>\n";
Geo::Parse::OSM->parse_file( 'file.osm', $addname );
print "</osm>\n";

Хм… Выглядит вроде несложно :slight_smile:

А что будет если попытаться добавить существующий тег с точно таким же значением?

Поменяет

Написал вроде. Остался косяк с юникодом.

Если я не делаю binmode STDOUT, ‘:utf8’; , то получается

Если делаю, то

Без binmode нормально работают обычные принты в стдаут, но не работает
print Geo::Parse::OSM->to_xml( $_[0] );

С binmode портится что-то другое.

Что делать-то?

Консоль у меня юникодная
[ilis@altus osm_perl]$ locale
LANG=ru_RU.UTF-8

ЗЫ. И сравнение не работает если в чешском нейме есть гачеки (умляуты их).

    $csname = $_[0]->{tag}->{'name'};
    if ( $hash{$csname} ne '' && $_[0]->{tag}->{'name:ru'} eq '') {

to_xml отдаёт уже готовый utf8, дополнительный фильтр не требуется.
Пиши его в отдельный файл.
Или если нужно именно с фильтром, то print decode( ‘utf8’, Geo::Parse::OSM->to_xml( $_[0] ) );

Может он его там два раза отдаёт?

И что делать со сравнением? Из сотни городов только полтора десятка отбираются.

Где-то теряешь кодировку. Где именно, вслепую угадать сложно :slight_smile:

Undefined subroutine &main::decode called at ./make_osm_cz.pl line 13, line 62.

ещё до кучи…

use Encode;

Если я просто печатаю принтами, то всё по-русски. Как доходит до модуля, там корявства.

С декоде тоже не всё хорошо, то ворнинги, то корявки:

[ilis@altus osm_perl]$ ./make_osm_cz.pl | grep name:ru
Wide character in print at ./make_osm_cz.pl line 16, line 62.








Wide character in print at ./make_osm_cz.pl line 16, line 2775.






Ну я ж говорю, где-то по дороге портится кодировка.
Вряд ли тут модуль виноват

А вот это вообще не работает:
$csname = decode( ‘utf8’, $_[0]->{tag}->{‘name’});

Cannot decode string with wide characters at /usr/lib/perl5/vendor_perl/i386-linux/Encode.pm line 160, line 23

Правильно, и не должно работать. В $_[0] там уже всё и так раскодировано.

По дороге откуда куда?

Может какие-то тесты написать?

Прога пока вот такая:


#!/usr/bin/perl

# use Encode;
# use utf8;
use Geo::Parse::OSM;

# binmode STDOUT, ':utf8';

my $ru; my $cs; my $csname;
my %hash = ();
my $addname = sub {
        $csname = $_[0]->{tag}->{'name'};
        # $csname = decode( 'utf8', $_[0]->{tag}->{'name'});
        if ( $hash{$csname} ne '' && $_[0]->{tag}->{'name:ru'} eq '') {
                $_[0]->{action} = 'modify';
                $_[0]->{tag}->{'name:ru'} = $hash{$csname};
                print Geo::Parse::OSM->to_xml( $_[0] );
                # print decode( 'utf8', Geo::Parse::OSM->to_xml( $_[0] ) );
        }
};

open(MYINPUTFILE, "<ru_cs_towns.txt");
while(<MYINPUTFILE>) {
        chomp;
        ($ru, $cs) = split /:/;
        $hash{$cs} = $ru;
        print "$cs --> $hash{$cs}\n";
}


print "<osm>\n";
Geo::Parse::OSM->parse_file( 'file.osm', $addname );
print "</osm>\n";

Результат такой:


...
Cheb --> Хеб
Chrudim --> Хрудим
Česká Lípa --> Ческа-Липа
České Budějovice --> Ческе-Будеёвице
...
  <node action="modify" id="86964510" version="4" timestamp="2008-11-04T13:10:12Z" uid="308" user="MichaelCollinson" changeset="676656" lat="48.9474349" lon="16.3134502" visible="true">
    <tag k="is_in" v="Czech Republic, Europe"/>
    <tag k="is_in:continent" v="Europe"/>
    <tag k="is_in:country_code" v="cz"/>
    <tag k="name" v="Miroslav"/>
    <tag k="name:ru" v="ÐиÑоÑлав"/>
    <tag k="place" v="town"/>
    <tag k="source" v="geonames.org,cs.wikipedia.org,nga.mil"/>
  </node>
  <node action="modify" id="86965801" version="3" timestamp="2008-11-04T13:09:50Z" uid="308" user="MichaelCollinson" changeset="676656" lat="50.5607811" lon="15.9128796" visible="true">
    <tag k="is_in" v="Czech Republic, Europe"/>
    <tag k="is_in:continent" v="Europe"/>
    <tag k="is_in:country_code" v="cz"/>
    <tag k="name" v="Trutnov"/>
    <tag k="name:ru" v="ТÑÑÑнов"/>
    <tag k="place" v="town"/>
    <tag k="source" v="geonames.org,cs.wikipedia.org,nga.mil"/>
  </node>

[ilis@altus osm_perl]$ cat ru_cs_towns.txt | wc -l
93
[ilis@altus osm_perl]$ ./make_osm_cz.pl | grep ‘“name”’ | wc -l
25

Cheb, Chrudim – обрабатываются
Česká Lípa, České Budějovice – нет

open MYINPUTFILE, ‘<:utf8’, “ru_cs_towns.txt”;

Нда… модуль заработал, обычные принты разломались.

С модулем википедии таких проблем не было. И вообще раньше с моим перлом таких проблем не было. Думаю, дело всё-таки в модуле.

Может какие-то тесты на эту тему подготовить и найти багу?

Нет там багов, есть недопонимание работы с кодировками.
Для начала почитать http://perldoc.perl.org/perlunicode.html

Ну а про то, что to_xml выдаёт готовый utf8 вместо внутренней кодировки, я уже говорил.

Да что ж такое то! Теперь йосм не хочет файл открывать!

Ага, надо вместо обязательно

Ну и вот результат трудов: http://www.openstreetmap.org/browse/changeset/6150621

До сих пор не пойму, что меня торкнуло этим заняться! :slight_smile: