web-dev-qa-db-ja.com

文字を交換するsedコマンド

私の入力ファイルのレイアウトは次のとおりです。mm/dd/yyyy,hh:mm,other fields
次のようにフォーマットする必要があります:yyyy-mm-dd hh:mm:00,other fields

サンプル入力:

01/02/1998,09:30,0.4571,0.4613,0.4529,0.4592,6042175
01/02/1998,09:45,0.4592,0.4613,0.4529,0.4571,9956023
01/02/1998,10:00,0.4571,0.4613,0.455,0.4613,8939555
01/02/1998,10:15,0.4613,0.4697,0.4571,0.4697,12823627
01/02/1998,10:30,0.4676,0.4969,0.4613,0.4906,28145145

サンプル出力:

1998-01-02 09:30:00,0.4571,0.4613,0.4529,0.4592,6042175
etc...

私は使用しようとしました:

sed -r 's/\(^[0-9][0-9])\(\/[0-9][0-9]\/)\(\/[0-9][0-9][0-9][0-9],)/\3\1\2/g
5
sed -e 's/\(..\)\/\(..\)\/\(....\),\(.....\),\(.*\)/\3-\1-\2 \4:00,\5/'

以下のコメントからの入力を含むように編集されました:

sed -e 's#\(..\).\(..\).\(....\),\(.....\),#\3-\1-\2 \4:00,#'
6
jhilmer

それは私のために働いた:

sed -r 's/([0-9]{2})\/([0-9]{2})\/([0-9]{4}),([0-9:]{5})/\3-\1-\2 \4:00/g'

2桁に一致(([0-9]{2}))、スラッシュ、2桁(([0-9]{2}))、スラッシュ、4桁(([0-9]{4}))、次に数字と:([0-9:]{5}))。ご希望の順序に置き換えてください:\3-\1-\2 \4:00(年-月-日時間:分:00)。

3
chaos
sed 'y|/|-|
     s/,*\(.....\)-*\([^,]*\)/\2-\1/
     s// \1:00/2
'    <infile

出力:

1998-01-02 09:30:00,0.4571,0.4613,0.4529,0.4592,6042175
1998-01-02 09:45:00,0.4592,0.4613,0.4529,0.4571,9956023
1998-01-02 10:00:00,0.4571,0.4613,0.455,0.4613,8939555
1998-01-02 10:15:00,0.4613,0.4697,0.4571,0.4697,12823627
1998-01-02 10:30:00,0.4676,0.4969,0.4613,0.4906,28145145

sedを使用すると、通常はそれほど努力する必要はありません。探している一致を明示的に列挙しようとしても、多くの場合、費用はかかりません。むしろ、通常は、いくつかのランドマーク(区切り文字)を指定して、パターンに暫定的なものを追加する方がはるかに簡単です。

上記のsed最初のy///は、/文字を-文字に変換します。次に、最初の非コンマ(少なくとも5つある場合)文字をパターン空間に参照し、次の4文字を\1として参照しますが、末尾の-は無視する可能性があります。 。続いて、^内の連続する\2not-comma文字を、パターン空間で次に出現するコンマの前と同じ数だけ参照します。結果(最初の置換の場合)は、mm-ddに一致する前に\1-に配置し、次に\2yyyyを配置します。したがって、それらを交換し、-を削除して、次のように反対側に新しいものを挿入します。

s/.../\2-\1/

そして最後に、同じパターンを別の目的で再利用します。私がする時:

s// \1:00/2

最後の正規表現を再利用するようにsedに指示しています//空のアドレスで示されます)しかし、今回はパターン空間でそのパターンの2番目のオカレンスを見つけます--which does今回は,*とコンマを一致させます-このフィールドと最後のフィールドを区切るコンマと一致します。また、HH:MM\1および(文字列の直後にコンマが続くため)''\2null文字列とも一致します。そこから残っているのは、\1をそれ自体の前に<space>が続き、その後に文字列が続くことです。間にあるコンマとヌル文字列の両方が編集されます。

と感じた場合はwould結局のところ、もう少し具体的になりますが、少し抽象化するだけでどれだけ簡単になるかを検討してください。正規表現が提供する主な利点は、最初に何が反復するのかを明確に理解するだけで、反復タスクを迅速かつ効率的に抽象化する手段を提供することです。

正規表現の作成自体が繰り返しの作業になる場合は、まあ...何かが足りない可能性があります。ただし、単純な正規表現構文の利点の1つは、tooが抽象化の非常に優れた候補になることが多く、簡単に実現できることです。

例えば:

d='[0-9][0-9]' T=$d:$d m=$d y=$d$d
sed -E "s|($m/$d)/($y),($T)|\2-\1 \3:00|;s|/|-|"
3
mikeserv

そして可能なawkソリューション:

awk 'BEGIN { FS = OFS = ","; } { split($1, d, "/"); $2 = d[3] "-" d[1] "-" d[2] " " $2 ":00"; $1 = ""; } { for (i = 2; i < NF; i++) printf("%s", $i OFS); printf("%s", $NF ORS);}' file
2
taliezin

少し異なるアプローチを取ることをお勧めします-タイムスタンプを解析してから、フォーマットされたタイムスタンプを吐き出します。そして、私はこれにPerlを使用します:

#!/usr/bin/Perl

use strict;
use warnings;

use Time::Piece;

my $input_format  = '%m/%d/%Y,%H:%M';
my $output_format = '%Y-%m-%d %H:%M:%S';

while (<>) {
    my ( $date, $time, @stuff ) = split(",");
    my $timestamp = Time::Piece->strptime( "$date,$time", $input_format );
    print join( ",", $timestamp->strftime($output_format), @stuff );
}

したがって、これを1つのライナーに減らすことができます。

Perl -MTime::Piece -lne '($date,$time,@stuff) = split; print join ( ',', Time::Piece->strptime( "$date,$time", "%m/%d/%Y,%H:%M" ) -> strftime("%Y-%m-%d %H:%M:%S"), @stuff);'

サンプルデータを使用して、吐き出します。

1998-01-02 09:45:00,0.4592,0.4613,0.4529,0.4571,9956023
1998-01-02 10:00:00,0.4571,0.4613,0.455,0.4613,8939555
1998-01-02 10:15:00,0.4613,0.4697,0.4571,0.4697,12823627
1998-01-02 10:30:00,0.4676,0.4969,0.4613,0.4906,28145145
2
Sobrique

これを使って:

sed -n 's_^\([^/]*\)/\([^\]*\)/\([^,]*\),\([^:]*\):\([^,]*\)_\3-\1-\2 \4:\5:00_p' file.txt
1
heemayl