Проблема в том, что CMD.exe ограничен 8-битными кодовыми страницами.Символы "Å
" и "å
" отображаются (в шведской Windows) на позиции в верхнем 8-битном диапазоне кодовой страницы 850, которые являются недопустимыми кодовыми точками в Unicode.
Если вам нужновыводите не-7-битные символы ASCII, рассмотрите возможность запуска PowerShell ISE.Если вы установите его правильно, он может справиться с любым символом (в выводе), который поддерживает используемый вами шрифт.Большим недостатком является то, что PowerShell ISE не является консолью и поэтому не позволяет вводить данные с консоли / клавиатуры с использованием STDIN.Вы можете обойти это, предоставив свои входные данные в качестве аргументов, из конвейера, в файле настроек или через элементы запроса графического интерфейса пользователя.
Чтобы настроить Windows PowerShell ISE для работы с UTF8:
Установите PowerShell, чтобы разрешить запуск локальных неподписанных пользовательских сценариев, запустив (в PowerShell с повышенными правами администратора):
Set-ExecutionPolicy RemoteSigned
Создание или редактирование файла "<Documents>\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1
"и добавьте что-то вроде:
perl -w -e 'print qq!Initializing with Perl...\n!;'
[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8;
(вам необходим бит Perl (или что-то эквивалентное) для изменения кодировки.)
В PowerShellПараметры ISE, установите шрифт Consolas.
В ваших сценариях perl всегда выполняйте:
binmode(STDOUT, ':encoding(UTF-8)');
binmode(STDERR, ':encoding(UTF-8)');
Мое решение проблемы ОП:
use strict;
use warnings;
my $row = 0;
use XML::LibXML;
binmode(STDOUT, ':encoding(UTF-8)');
binmode(STDERR, ':encoding(UTF-8)');
@ARGV or die "No arguments!\n";
my $ort = shift @ARGV;
print "\n\n\nGetting weather report for \"$ort\"\n";
my $url = join('', "http://www.yr.no/place/Sweden/Västra_Götaland/",$ort,"/forecast_hour_by_hour.xml");
my $dom = XML::LibXML->load_xml(location => $url);
print "\n\nSee below the weather for ", $ort, ":\n\n";
foreach my $weatherdata ($dom->findnodes('//time')) {
if($row != 10){
my $temp = $weatherdata->findvalue('./temperature/@value');
my $value = $weatherdata->findvalue('./@from');
my $valuesub = substr $value, 11, 5;
print "At ", $valuesub, " the temperature will be: ", $temp, "C\n";
$row++;
}
}
print "\n\n";
Выход:
(работает около 2018-06-09T14: 05 UTC; 16:05 CEST (часовой пояс Швеции)):
PS (censored)> perl -w $env:perl5lib\Tests\Amal-Test.pl "Åmål"
Getting weather report for "Åmål"
See below the weather for Åmål:
At 17:00 the temperature will be: 27C
At 18:00 the temperature will be: 26C
At 19:00 the temperature will be: 25C
At 20:00 the temperature will be: 23C
At 21:00 the temperature will be: 22C
At 22:00 the temperature will be: 21C
At 23:00 the temperature will be: 20C
At 00:00 the temperature will be: 19C
At 01:00 the temperature will be: 18C
At 02:00 the temperature will be: 17C
Еще одно примечание:
Опора на данные, которые всегда находятся в точном положении в строке, может быть не лучшей идеей.
Вместо:
my $valuesub = substr $value, 11, 5;
, возможно, стоит вместо этого сопоставить его с регулярным выражением:
if ($value =~ /T((?:[01]\d|2[0-3]):[0-5]\d):/) {
my $valuesub = $1;
print "At ", $valuesub, " the temperature will be: ", $temp, "C\n"; }
else {
warn "Malformed value: $value\n";
}