J'ai quelques tables (table.txt) comme suit:
YEAR MONTH DAY RES 1971 1 1 1345 1971 1 2 1265 1971 1 3 1167
La longueur de chaque série chronologique va du 1.1.1971
au 31.12.2099
. Malheureusement, certaines séries chronologiques manquent d'années bissextiles et leurs valeurs (par exemple, l'année 1972 est une année bissextile, donc le mois de février devrait avoir 29 jours, mais mes séries chronologiques n'ont que 28 jours en février 1972). Pour des exemples dans mes arrays actuels, la fin du mois de février 1972 est présentée comme suit:
YEAR MONTH DAY RES 1972 2 27 100 1972 2 28 101 1972 3 1 102
C'est faux, car cela ne tient pas count des années bissextiles. Au lieu de cela, j'aimerais inclure dans mes séries temporelles chaque jour manquant (évidemment le 29 février) de chaque année bissextile dans ma série chronologique, en extrapolant la valeur avec le précédent et le jour suivant comme suit:
YEAR MONTH DAY RES 1972 2 27 100 1972 2 28 101 1972 2 29 101.5 1972 3 1 102
Y at-il un moyen de le faire en utilisant shell / bash?
Peut-être quelque chose comme:
awk ' function isleap(y) { return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0) } $2 == 3 && $3 == 1 && isleap($1) && last_day != 29 { print $1, 2, 29, (last_data + $4) / 2 } {print; last_day = $3; last_data = $4}' file
Solution Perl:
#!/usr/bin/perl use warnings; use ssortingct; use Time::Piece; print scalar <>; # Skip the header. while (<>) { my ($year, $month, $day, $res) = split; my $t = 'Time::Piece'->strptime("$year $month $day", '%Y %m %d'); if ($t->is_leap_year && 2 == $month && 28 == $day) { print; $_ = <>; my ($year2, $month2, $day2, $res2) = split; die "Expected March the 1st: $_" unless $year == $year2 && 3 == $month2 && 1 == $day2; print join("\t", $year, 2, 29, ($res + $res2) / 2), "\n"; } print; }
Enregistrer sous fix_feb29.pl
. Puis courez
for file in *.txt ; do fix_feb29.pl -i~ "$file" done
Je pensais juste à cela et, en raison de la façon dont les années bissextiles alternent toutes les deux années paires, ce qui suit est vrai:
([13579][26]|[02468][048]) == leap year
Fondamentalement, les années bissextiles se produisent les années 2 et 6 pour les années impaires, mais les années 4 et 8 pour les années paires et au tournant de toutes les deux décennies.
Et ainsi vous pouvez faire:
sed -e' /[02468] * 2 * 28 /!b'\ -e'h;/[13579][26] * 2 / G' \ -e' /[02468][048] * 2 /G' \ -e' /\n/s/ 28 / 29 /2' \ -eP\;D <in >out
… qui findait, doublerait, puis modifierait toutes les lignes du 28 février en input seulement pour les années bissextiles quel que soit le sharepoint départ de n'importe quelle boucle d'alternance.
C'était mon premier instinct:
sed -e'/\([02648] * 2 * 2\)8 /!b' \ -e:n -e'n;//!bn' -e'p;s//\19 /' <in
… ce qui n'était qu'une légère adaptation à ma réponse à votre autre question , mais qui ne fonctionnera que pour chaque série où la première année paire rencontrée n'est pas une année bissextile car elle fonctionne par alternance.
J'ai testé les deux sed
s contre mon file de test de votre autre question . Les infiltrés avaient déjà des années bissextiles, et le code que je générais était également dans la réponse, mais les deux travaillaient pour une série commençant en 1970, bien que la première ne se briserait pas de toute façon:
1970 2 27 58 1970 2 28 59 1970 3 1 60 1972 2 27 58 1972 2 28 59 1972 2 29 59 1972 2 29 60 1972 3 1 61 1974 2 27 58 1974 2 28 59 1974 3 1 60 1976 2 27 58 1976 2 28 59 1976 2 29 59 1976 2 29 60 1976 3 1 61 1978 2 27 58 1978 2 28 59 1978 3 1 60 1980 2 27 58 1980 2 28 59 1980 2 29 59 1980 2 29 60 1980 3 1 61