回答:
私はsed
この質問を投稿してからまもなく答えを出しました。sed
これまで他の誰も使用していませんので、ここにあります:
sed '$!N;/^\(.*\)\n\1$/d;P;D'
より一般的な問題(3組の行を削除するのはどうですか?または4、5の場合はどうですか?)で少し遊んでみると、次の拡張可能なソリューションが提供されました。
sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
行のトリプルを削除するために拡張されました:
sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
または、四角形の行を削除するには:
sed -e ':top' -e '$!{/\n.*\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1\n\1$/d;P;D' temp
sed
他のほとんどのオプションに比べて追加の利点があります。これは、実際に重複をチェックする行数よりも多くのメモリストレージを必要とせずに、ストリームで実際に動作する能力です。
以下のようcuonglmはコメントで指摘し、Cにロケールを設定すると、正常にマルチバイト文字を含む行を削除するために失敗を避けるために必要です。したがって、上記のコマンドは次のようになります。
LC_ALL=C sed '$!N;/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
# Etc.
それは非常にエレガントではありませんが、私が思いつくことができるほど簡単です:
uniq -c input | awk '{if ($1 % 2 == 1) { print substr($0, 9) }}'
substr()はuniq
出力を削除します。これは、行の重複が9,999,999を超えるまで機能します(この場合、uniqの出力は9文字を超える可能性があります)。
uniq -c input | awk '{if ($1 %2 == 1) { print $2 } }'
、同じように機能するように見えました。substr
バージョンが優れている理由は何ですか?
$2
を印刷するループは$NF
より堅牢ではないでしょうか?
foo bar
。
awk
以下のこのスクリプトを試してください:
#!/usr/bin/awk -f
{
if ((NR!=1) && (previous!=$0) && (count%2==1)) {
print previous;
count=0;
}
previous=$0;
count++;
}
END {
if (count%2==1) {
print previous;
}
}
lines.txt
ファイルはソートされていると想定されます。
テスト:
$ chmod +x script.awk
$ ./script.awk lines.txt
a
d
e
入力がソートされている場合:
perl -0pe 'while(s/^(.*)\n\1\n//m){}'
pineapple\napple\ncoconut
、実行してみてくださいpinecoconut
。出力はです。
\n
を$
指定する代わりに使用しているのか疑問に思っていましたが/m
、使用$
すると削除された行の代わりに空白行が残ることに気付きました。よさそうだ。ノイズを追加しただけなので、間違ったバージョンを削除しました。:)
各レコードのハッシュを使用してawkを選択した質問を理解したので、この場合はRS = \ nと仮定していますが、他の種類の配置を考慮するように変更することができ、パラメータまたは小さなダイアログを使用して、奇数ではなく偶数の担当者。すべての行がハッシュとして使用され、そのカウントが増加します。ファイルの最後で、配列がスキャンされ、レコードの偶数カウントごとに出力されます。チェックするためにカウントを含めていますが、a [x]を削除するだけでその問題を解決できます。
HTH
カウントラインコード
#!/usr/bin/nawk -f
{a[$0]++}
END{for (x in a) if (a[x]%2!=0) print x,a[x] }
サンプルデータ:
a
One Sunny Day
a
a
b
my best friend
my best friend
b
c
c
c
One Sunny Day
c
d
my best friend
my best friend
d
d
d
One Sunny Day
d
e
x
k
j
my best friend
my best friend
サンプル実行:
countlines feed.txt
j 1
k 1
x 1
a 3
One Sunny Day 3
d 5
e 1
awk
コードですが、残念ながらawk
連想配列はまったく順序付けられておらず、順序を維持していません。
sort
。
!=0
かによって暗示されるawk
には、この還元性を作り、真/偽の値に変換数awk '{a[$0]++}END{for(x in a)if(a[x]%2)print x}'
シェル構造を使用して、
uniq -c file | while read a b; do if (( $a & 1 == 1 )); then echo $b; fi done
$b
)。
楽しいパズル!
Perlの場合:
#! /usr/bin/env perl
use strict;
use warnings;
my $prev;
while (<>) {
$prev = $_, next unless defined $prev; # prime the pump
if ($prev ne $_) {
print $prev;
$prev = $_; # first half of a new pair
}
else {
undef $prev; # discard and unprime the pump
}
}
print $prev if defined $prev; # possible trailing odd line
Haskellの場合:
main :: IO ()
main = interact removePairs
where removePairs = unlines . go . lines
go [] = []
go [a] = [a]
go (a:b:rest)
| a == b = go rest
| otherwise = a : go (b:rest)
Haskellで簡潔に:
import Data.List (group)
main = interact $ unlines . map head . filter (odd . length) . group . lines
バージョン:「デリミタ」を使用して内部ループを簡素化します(最初の行が __unlikely_beginning__
で、テキストがline:__unlikely_ending__
で終わらないことを前提とし、入力された行の最後に特別な区切り行を追加します。アルゴリズムは両方を想定できます:)
{ cat INPUTFILE_or_just_- ; echo "__unlikely_ending__" ; } | awk '
BEGIN {mem="__unlikely_beginning__"; occured=0; }
($0 == mem) { occured++ ; next }
( occured%2 ) { print mem ;}
{ mem=$0; occured=1; }
'
そう :
C
。そうしないと、マルチバイトロケールで、そのロケールの無効な文字が原因でコマンドが失敗します。