다음과 같은 데이터 파일이 있습니다.
1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 . . .
1 0 4 4 3 1 2 0 0 0 3 1 1 2 1 1 1 1 1 1 0 1 1 3 . . .
0 0 0 0 0 0 0 3 3 1 1 2 3 2 1 2 2 3 1 2 3 1 2 2 . . .
.
.
.
먼저 동일한 5개 값 사이에 공백을 삽입하고 싶습니다. 첫 번째 행을 보고 동일한 숫자 5개를 열에 넣은 다음 이러한 그룹 문자 사이에 공백을 삽입하지 않으려고 합니다. 첫 번째 단계:
1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 . . .
1 0 4 4 3 1 2 0 0 0 3 1 1 2 1 1 1 1 1 1 0 1 1 3 . . .
0 0 0 0 0 0 0 3 3 1 1 2 3 2 1 2 2 3 1 2 3 1 2 2 . . .
.
.
.
두 번째 단계(출력):
11111 11111 1 22222 222 33333 . . .
10443 12000 3 11211 111 10113 . . .
00000 00331 1 23212 231 23122 . . .
.
.
.
또한 실제 데이터에서는 다양한 그룹 크기를 시도해보고 싶을 수도 있습니다. 그래서 유연한 스크립트가 필요합니다. 제안 사항이 있나요?
답변1
이것은 awk 스크립트입니다. 5
숫자만 변경하면 다른 그룹화를 수행할 수 있습니다 .
awk '
NR==1{
previous = $1
for(i = 1;i<=NF+1;i++)
if($i!=previous){
col[++numcol] = i
previous = $i
}
}
{ j = 1; start = 1
for(i = 1;i<NF;i++){
printf "%s",$i
if(i==col[j]-1){printf " "; start = col[j++]}
else if((i-start+1)%5==0)printf " "
}
printf "%s\n",$NF
}'
첫 번째 부분은 행 1만 처리하고 배열에 있는 각 동일한 숫자 집합의 시작 열을 수집합니다 col
. 두 번째 부분은 시작 열의 5열이나 시퀀스 끝 부분을 제외하고 각 필드를 무제한으로 인쇄합니다.
답변2
다른 변형앗
awk '
NR==1{
for(i=2;i<=NF;i++){
count++
if($(i-1)!=$i || count>4){
D[i]=1
count=0
}
}
}
{
for(i in D)
$i=" "$i
print
}
' OFS="" data.file >new.file
그리고sed
sed -re '
s/ +//g;s/^/\n/
' -f <(
sed -r '
s/(. )\1*/s_\\n(&)_\n/g
s/\S /./g
s/\n\s*/\\1 \\n_\n/g
s/\\n[^\n]*\n$/ \\n__/
1q
' data.file
) -e '
s/\S{5}/& /g
' data.file >new.file
답변3
한 가지 가능한 방법은 Perl을 사용하는 것입니다.짐 등에서 꺼내다파일의 첫 번째 줄에서 구성된 템플릿을 사용하는 함수입니다.
공백을 제거한 후 반복된 역참조가 포함된 정규식을 사용하여 동일한 문자의 가장 긴 연속 문자열을 찾고 maxwidth
해당 위치를 배열에 저장합니다. 필드 너비는 배열의 인접한 요소를 빼서 추출되고 함수 A5A5A1A5A3A5A3
에 전달될 양식의 적절한 템플릿 문자열에 매핑됩니다.unpack
#!/usr/bin/perl -l
use strict;
use warnings;
my $filename = shift or die "Usage: $0 FILENAME MAXWIDTH\n";
my $maxwidth = shift or die "Usage: $0 FILENAME MAXWIDTH\n";
open my $infile, $filename or die "Could not open $filename: $!";
my $n = $maxwidth-1;
my $template;
while( my $line = <$infile> ) {
$line =~ s/\s+//g;
if ($. == 1) {
my @ends = (0);
while ($line =~ /(.)\g1{0,$n}/g) {
push(@ends, pos $line);
}
my @fieldwidths = map $ends[$_] - $ends[$_-1], 1 .. $#ends;
# http://stackoverflow.com/a/29821158/4440445
$template = join "", map { 'A' . $_ } @fieldwidths;
# http://stackoverflow.com/a/2725663/4440445
}
my @fields = unpack($template, $line);
print join " ", @fields;
}
close $infile;