tsv / csvの大きな列の間で文字を切り取る方法は?

tsv / csvの大きな列の間で文字を切り取る方法は?

CSVファイルがあります。

1,abcde aa aaaa aaa aaaa abcde,4
2,efghi ooo oooo ooo oooo efghi,5

最初と最後の5文字で2列目を切り取り、3点で埋めるにはこの列が必要です。この目標を達成する方法は?

1,abcde ... abcde,4
2,efghi ... efghi,5

答え1

解決sed

sed -E 's/(.*,.{5}).*(.{5},.*)/\1...\2/'

2番目の「列」(フィールド)が9文字以下の場合、入力は変更されずに保持されますが、正確に10文字でも「」が挿入されます(任意の文字を置き換えなくても)。

     入力する                       出力
9,abcdefghi,z 9,abcdefghi,z
(お金はそのまま維持してください)
10,abcdefghij,z 10,abcde...fghij,z
(参考としてこれはもっと長く入力より。 )

キャスの答え2番目のフィールドが置き換えるのに十分な長さであることを明示的に確認することをお勧めします。私の答えは質問をすることだから説明する(3つのポイントを挿入)表示されるもの(スペース+ドット3つ+スペースを挿入または入力にスペースを残す)の代わりに、最初の5つと最後の5つの間に4つ以上の異なる文字がある場合に恩恵を受けます。この問題を処理するには、次のコマンドを使用できます。

sed -E 's/(.*,.{5}).{4,}(.{5},.*)/\1...\2/'
     入力する                     出力
10,abcdefghij,z 10,abcdefghij,z
(お金はそのまま維持してください)
13,abcdefghijklm,z 13,abcdefghijklm,z
(まだ変化はありません)
14,abcdefghijklmn,z 14,abcde...jklmn,z
(入力した文字より1文字短い)
20,abcdefghijklmnopqrst,z 20,abcde...pqrst,z

.{4,}4つ以上の文字を一致させます。もちろん負数ではなく整数4に変更する。たとえば、繰り返されるcasに対して提案された回答を使用するには、をmin=20使用します  .{11,}

答え2

$ 2が切り捨てられる長さ(15文字:5文字+スペース+ 3点+スペース+ 5文字)より長くない場合は、実行する価値はありません。

$ awk -F, '
  BEGIN {OFS=FS; min=15};
  length($2) > min { $2 = substr($2,1,5)  " ... " substr($2, length($2)-4) }1' input.csv 
1,abcde ... abcde,4
2,efghi ... efghi,5
3,short field,5

$ cat input.csv 
1,abcde aa aaaa aaa aaaa abcde,4
2,efghi ooo oooo ooo oooo efghi,5
3,short field,5

または、length($2)各入力行に対して一度だけ計算します。 (OFSと最小値を設定する他の方法も表示されます。)

awk -F, -v OFS=, -v min=15 '
  { L=length($2) };
  L > min { $2 = substr($2,1,5)  " ... " substr($2, L-4) }1' input.csv

1それよりもはるかに長くなければ、実行する価値はありません。したがって、少なくとも20文字です。

答え3

現在の例で必要なものは次のとおりです。

$ sed 's/ .* / ... /' file
1,abcde ... abcde,4
2,efghi ... efghi,5

または、実際には2番目のフィールドでのみ作業する必要がある場合は、次のようにします。

$ awk 'BEGIN{FS=OFS=","} {sub(/ .* /," ... ",$2)}1' file
1,abcde ... abcde,4
2,efghi ... efghi,5

これが必要なものでない場合は、質問を編集して適用されない場合を含む、より代表的な入力/出力の例を表示してください。

答え4

使用幸せ(以前のPerl_6)

raku -pe 's/ \, <( (<alnum>**5) .* (<alnum>**5) )> \, /$0 ... $1/;' 

または

raku -pe 's/ \, <( $<head>=[<alnum>**5] .* $<tail>=[<alnum>**5] )> \, /$<head> ... $<tail>/;' 

入力例:

1,abcde aa aaaa aaa aaaa abcde,4
2,efghi ooo oooo ooo oooo efghi,5

出力例(上記の2つのコード例):

1,abcde ... abcde,4
2,efghi ... efghi,5

上記の答えは幸せプログラミング言語はPerlプログラミング言語ファミリーに属します。上記の2つの答えは、基本的にcolumn_1のカンマの右側にある最初の5文字<alnum>(文字+アンダースコア+ <digits>)という仮定に基づいています。より広い範囲の文字を処理する方法の詳細については、以下のコードを参照してください。

Rakuは、より強力で読みやすいように設計された新しい正規表現エンジンを使用しています。最初の例では番号付きのキャプチャ($0、、$1)が使用され、2番目の例ではキャプチャ($<head>、、$<tail>)が使用されます。上記のコードのハイライトには、1)数字以外の文字を賢明にエスケープ処理\,(推測する必要はありません)、[ … ]正規表現「原子」を角括弧でグループ化、角括弧でキャプチャ、( … )最初から番号付けキャプチャ、一般数量子$0として使用します(**min..max例:**5)、キャプチャマーカーを使用して一致オブジェクトの外側のテキストを描画します<( … )>。これにより、カンマ(一致オブジェクトの外側)は誤って削除されません。

上記の答えは、(文字、アンダースコア)+で構成されるRakuの組み込み<alnum>文字クラスを使用します。しかし、より多様な文字を切り取ることもできます。組み込みの文字クラスをカスタム(カスタムおよび/または列挙型)文字クラスに置き換えることができます。カスタム文字クラスは、空白以外の文字(数字の小数点など)からコンマを減算し、マイナスコンマを使用します。<alpha><digits><alnum><+[\S]-[,]><+[\S]-[,]>+[\S]-[,]

以下に合理的な結果を示します。たとえば、1行と2行は適切に短縮されていますが、line_3 / column_2(4文字のカンマ以外の長さ)は短すぎて切り捨てることはできません。 (「短距離フィールド」に触発された@casに感謝します):

raku -pe 's/ \, <(( <+[\S]-[,]>**5) .* ( <+[\S]-[,]>**5 ))> \, /$0 ... $1/;'  

入力例:

1,$2.37 aa aaaa aaa aaaa abcde,1_end
2,##IN: ooo oooo ooo oooo efghi,2_end
3,#OUT, ooo oooo ooo oooo efghi,3_end
4,short field,4_end
5,thin ice,5_end

出力例:

1,$2.37 ... abcde,1_end
2,##IN: ... efghi,2_end
3,#OUT, ooo oooo ooo oooo efghi,3_end
4,short ... field,4_end
5,thin ice,5_end

https://raku.org

関連情報