#! /usr/local/bin/perl -w # # tenki - a tool to get weather information in Japan. # # Copyright (C) 1999 Satoru Takabayashi # All rights reserved. # This is free software with ABSOLUTELY NO WARRANTY. # # You can redistribute it and/or modify it under the terms of # the GNU General Public License version 2. # # NOTES: # # This program gets weather information from # use strict; use LWP::Simple; use Getopt::Long; use IO::File; my $VERSION = "1999-04-20"; # default my $prefecture = '奈良'; # 都道府県名 my $region = "北部"; # ○○地方 my %prefecture_codes = ( '北海' => 's1', '青森' => 's2', '岩手' => 's3', '宮城' => 's4', '秋田' => 's5', '山形' => 's6', '福島' => 's7', '茨城' => 's8', '栃木' => 's9', '群馬' => 's10', '埼玉' => 's11', '千葉' => 's12', '東京' => 's13', '神奈川' => 's14', '新潟' => 's15', '富山' => 's16', '石川' => 's17', '福井' => 's18', '山梨' => 's19', '長野' => 's20', '岐阜' => 's21', '静岡' => 's22', '愛知' => 's23', '三重' => 's24', '滋賀' => 's25', '京都' => 's26', '大阪' => 's27', '兵庫' => 's28', '奈良' => 's29', '和歌山' => 's30', '鳥取' => 's31', '島根' => 's32', '岡山' => 's33', '広島' => 's34', '山口' => 's35', '徳島' => 's36', '香川' => 's37', '愛媛' => 's38', '高知' => 's39', '福岡' => 's40', '佐賀' => 's41', '長崎' => 's42', '熊本' => 's43', '大分' => 's44', '宮崎' => 's45', '鹿児島' => 's46', '沖縄' => 's47'); my $CacheFile = "$ENV{HOME}/.tenki-cache"; my $ExpirationTime = 3600 * 3; # 3 hours my $C = '(?:[\x21-\x7e]|[\xa1-\xfe][\xa1-\xfe])'; my $K = '(?:[\xa1-\xfe][\xa1-\xfe])'; main (); sub main () { if (@ARGV > 0) { ($prefecture, $region) = parse_commandline(); my $weather = get_weather($prefecture, $region); show_weather($weather); } else { my $weather = ""; if (-e $CacheFile) { my $mtime = (stat($CacheFile))[9]; my $time = time; if ($mtime + $ExpirationTime < $time) { # cache file is expired # print "CACHE FILE IS EXPIRED!\n"; $weather = get_weather($prefecture, $region); } else { $weather = load_cache(); } } else { $weather = get_weather($prefecture, $region); } show_weather($weather); save_cache($weather); } } sub save_cache ($) { my ($weather) = @_; my $fh = new IO::File; $fh->open(">$CacheFile") || die $!; print $fh $weather; } sub load_cache ($) { my $fh = new IO::File; $fh->open($CacheFile) || die $!; my $weather = join '', <$fh>; return $weather; } sub show_weather ($) { print @_; } sub get_weather ($$) { my ($prefecture, $region) = @_; my $date = ""; my $prefecture_type = ""; my $current_region = ""; my $probability = ""; my @weathers = (); my @temperatures = (); my @probabilities = (); my $region_flag = 0; my $weather_count = 0; my $temperature_count = 0; my $url = "http://www.wni.co.jp/cww/docs/yoho/$prefecture_codes{$prefecture}.html"; for (split "\n", get($url)) { chomp; s/<[^>]+alt=([^>]+)>/$1/g; # 天気情報は alt 属性 s/<[^>]+>//g; last if (/$C*<.+>/); if (/$C*(\d+)月(\d+)日(\d+)時/){ # 日時 $date = $_; } elsif (/$C*.+(都|道|府|県)$/){ # 都道府県 $prefecture_type = $1; } if (/$C*?($K+)地方/){ if ($region eq "") { $current_region = "[$1]"; $region_flag = 1; } elsif (/$region/) { $region_flag = 1; } else { $region_flag = 0; } push @probabilities, $probability if $probability ne ""; $probability = ""; } next if $region_flag == 0; if (/$C*(晴|曇|雨|雪)/){ # 天気 s/→/のち/; s/|/ときどき/; if ($weather_count % 2 == 0) { push @weathers, "今日の予想天気$current_region: $_"; } else { push @weathers, "明日の予想天気$current_region: $_"; } $weather_count++; } elsif (/$C*℃/){ # 気温 s/($C*)℃/$1/g; if (s!($C*)/!$1/!) { push @temperatures, sprintf("明日の最低最高$current_region: %2s℃", $_); } else { if ($temperature_count % 2 == 0) { push @temperatures, sprintf("今日の最高気温$current_region: %2s℃", $_); } else { push @temperatures, sprintf("明日の最低気温$current_region: %2s℃", $_); } $temperature_count++; } } elsif (/\d+%/){ # 降水確率 s/-//g; s/%(\d)/% $1/g; my @tmp = split " +", $_; grep {s/(\d+)/sprintf("%3d", $1)/ge} @tmp; $probability .= "降水確率(6h毎)$current_region:" if $probability eq ""; $probability .= " " . join ' ', @tmp; next; } } push @probabilities, $probability if $probability ne ""; $probability = ""; my $title = "$prefecture$prefecture_type$region地方# $date"; my $weathers = join "\n", @weathers; my $temperatures = join "\n", @temperatures; my $probabilities = join "\n", @probabilities; return join "\n", $title, $weathers, $temperatures, $probabilities, $url, ""; } sub parse_commandline () { my $version; my $help; my $tmp_prefecture; my $tmp_region; # Getopt::Long::Configure('bundling'); Getopt::Long::config('bundling'); # deprecated name GetOptions('p|prefecture=s' => \$tmp_prefecture, 'r|region=s' => \$tmp_region, 'v|version' => \$version, 'h|help' => \$help, ); if ($version) { print "tenki version $VERSION\n" ; exit 0; } elsif ($help) { print "tenki [-p 都道府県] [-r 地方] [都道府県] [地方]\n"; print " see for web browsing.\n"; exit 1; } if (defined $tmp_prefecture || defined $tmp_region || defined $ARGV[0] || defined $ARGV[1]) { $prefecture = ""; $region = ""; } $prefecture = $tmp_prefecture if defined $tmp_prefecture; $region = $tmp_region if defined $tmp_region; $prefecture = $ARGV[0] if defined $ARGV[0]; $region = $ARGV[1] if defined $ARGV[1]; $prefecture =~ s/(都|道|府|県)$// unless $prefecture eq "京都"; $region =~ s/地方$//; if ($prefecture eq "") { print "only a region is set but not a prefecture.\n"; exit 1; } return ($prefecture, $region); }