我有一些用 SED、AWK 和 Perl 決議的文本檔案資料。
product {
name { thing1 }
customers {
mary { }
freddy { }
bob {
spouse betty
}
}
}
從“客戶”部分,我試圖獲得類似于以下內容的輸出:
mary{ }
freddy{ }
bob{spouse betty}
使用:sed -n -e "/customers {/,/}/{/customers {/d;/}/d;p;}" $file'
這是輸出:
mary { }
freddy { }
bob {
spouse betty
}
如何將“bob”客戶連接到一行并洗掉多余的空格?這個特定輸出的主要原因是我正在撰寫一個腳本來獲取文本檔案中的“客戶”欄位和其他欄位,然后將它們輸出到 csv 檔案。看起來像這樣。我知道這在另一種語言中可能會更容易,但 bash 是我所知道的。
output.csv
product,customers,another_column
thing1,mary{ } freddy{ } bob{spouse betty},something_else
uj5u.com熱心網友回復:
資料恰好有效tcl串列語法:
set f [open "input.file"]
set data [dict create {*}[read $f]]
close $f
set name [string trim [dict get $data product name]]
dict for {key val} [dict get $data product customers] {
lappend customers [format "%s{%s}" $key [string trim $val]]
}
set f [open "output.csv" w]
puts $f "product,customers,another_column"
puts $f [join [list $name [join $customers] "something_else"] ,]
close $f
創建 output.csv 與
product,customers,another_column
thing1,mary{} freddy{} bob{spouse betty},something_else
uj5u.com熱心網友回復:
編輯 見結束以產生完整的所需輸出
這是正則運算式對于它,可能幾乎可以使用任何語言,以字串的形式在整個檔案上運行。就目前而言,這假設客戶下只能有一層嵌套,換句話說bob,不能有{ pets { dog } }或類似的嵌套。
提取customers部分內容
/customers\s*{\s* ( (?: [^{] {[^}]*} ) )/x;
然后將換行符 空格折疊成一個空格
s/\n\s / /g;
然后從字串中修剪空格,例如bob { spouse },但不是mary { }
s/{\s ([^}] ) \s }/{$1}/gx;
如果bob和作業人員真的只能是單詞字符,那么[^{}]我們可以使用 far niceer來代替\w。
總而言之,在似乎需要的 Perl 命令列程式中
perl -wE'die "file?\n" if not @ARGV;
$d = do { local $/; <> };
($c) = $d =~ /customers\s*{\s* ( (?: [^{] {[^}]*} ) )/x;
$c =~ s/\n\s / /g;
$c =~ s/{\s ([^}] ) \s }/{$1}/gx;
say $c
' data.txt
這將列印問題中給出的資料
瑪麗 { } 弗雷迪 { } 鮑勃 {配偶貝蒂}
例如,將每個客戶列印在單獨的行上
say for split /(?<=\})\s /, $c;
(成為代碼的最后一行)
我現在意識到還有更多要捕獲和列印的內容,如上一段所述。添加到正則運算式的開頭以捕獲name,并添加所需的列印
perl -wE'die "file?\n" if not @ARGV;
$d = do { local $/; <> };
($n, $c) = $d =~ /name\s*{\s* ([^}] ) \s*} .*? customers\s*{\s* ( (?: [^{] {[^}]*} ) )/sx;
$n =~ s/^\s |\s $//g;
$c =~ s/\n\s / /g;
$c =~ s/{\s ([^}] ) \s }/{$1}/gx;
say "product,customers,another_column"
say "$n,$c,something_else"
' data.txt > output.csv
重定向到output.csv的輸出如問題所示。
uj5u.com熱心網友回復:
僅使用您展示的樣品。在 GNU 中awk,您可以嘗試以下awk代碼。我們可以在單個 GNU中完成awk,我們不需要將您的sed命令輸出傳遞給任何其他工具。只需將您的 Input_file 傳遞給該awk程式即可。
第一個解決方案:customers要在}其右括號和沒有起始空格的值之間獲得輸出,awk解決方案。
awk -v RS='\n[[:space:]] customers {[[:space:]]*.*\n[[:space:]] }' '
RT{
sub(/^\n[[:space:]] [^ ]* {[[:space:]]*\n/,"",RT)
sub(/\n[[:space:]] }/,"",RT)
match(RT,/(.*{)[[:space:]]*([^\n]*)(.*)/,arr)
sub(/^[[:space:]] /,"",arr[1])
sub(/\n/,"",arr[2])
gsub(/\n|^[[:space:]] /,"",arr[3])
gsub(/\n[[:space:]] /,"\n",arr[1])
gsub(/ {/,"{",arr[1])
print arr[1] arr[2] arr[3]
}
' Input_file
輸出如下:
mary{ }
freddy{ }
bob{spouse betty}
第二種解決方案:要在值之前有起始空格,請嘗試以下代碼。
awk -v RS='\n[[:space:]] customers {[[:space:]]*.*\n[[:space:]] }' '
RT{
sub(/^\n[[:space:]] [^ ]* {[[:space:]]*\n/,"",RT)
sub(/\n[[:space:]] }/,"",RT)
match(RT,/(.*{)[[:space:]]*([^\n]*)(.*)/,arr)
sub(/\n/,"",arr[2])
gsub(/\n|^[[:space:]] /,"",arr[3])
print arr[1] arr[2] arr[3]
}
' Input_file
輸出如下:
mary { }
freddy { }
bob {spouse betty}
說明:簡單的解釋是在 GNUawk設定 RS(記錄分隔符)\n[[:space:]] customers {[[:space:]]*.*\n[[:space:]] }中只匹配所需的匹配項。然后在該程式的主塊中,awk根據(替換函式)的要求洗掉所有不必要的(不需要的字串部分)sub,然后使用match正則運算式函式,(.*{)[[:space:]]*([^\n]*)(.*)其值被存盤到一個名為的陣列中arr,然后我替換所有換行符/spaces ,然后用 RT 列印當前行的值。
uj5u.com熱心網友回復:
以下代碼示例演示了提供的示例資料的最原始決議器。
此代碼恢復資料結構,然后可以以任何可以想象的方式使用,例如存盤為CVS、JSON、YAML檔案。
在現實生活中,輸入資料可能完全不同,這段代碼可能無法正確處理它。
提供的代碼僅用于教育目的。
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my $data = do { local $/; <DATA> };
$data =~ s/\n/ /g;
$data =~ s/ / /g;
say Dumper parse($data);
exit 0;
sub parse {
my $str = shift;
my $ret;
while( $str =~ /^(\S ) \{ (\S ) \{ \S / ) {
if( $str =~ /^(\S ) \{ (\S ) \{ ([^}] ?) \{(. ?)\}/ ) {
$ret->{$1}{$2}{$3} = $4;
$ret->{$1}{$2}{$3} =~ s/(^\s |\s $)//g;
$str =~ s/^(\S ) \{ (\S ) \{(. ?)\{(.*?)\}/$1 \{ $2 \{/;
}
if( $str =~ /^(\S ) \{ (\S ) \{\s*([^{] ?)\s*\}/ ) {
$ret->{$1}{$2} = $3 if length($3) > 1;
$str =~ s/^(\S ) \{ \S \{\s*[^\}] \s*\}/$1 \{/;
}
}
return $ret;
}
__DATA__
product {
name { thing1 }
customers {
mary { }
freddy { }
bob {
spouse betty
}
}
}
輸出
$VAR1 = {
'product' => {
'customers' => {
'bob' => 'spouse betty',
'freddy' => '',
'mary' => ''
},
'name' => 'thing1'
}
};
uj5u.com熱心網友回復:
也許ed
ed -s file.txt <<-'EOF'
%s/^[[:space:]]*//
?{?;/^}/j
%s/^\([^\{]*\) \(.*\)$/\1\2 /
/^customers/ 1;/^}/-1j
s/^/thing1,/
s/ *$/,someting_else/
p
Q
EOF
使用臨時檔案,寫入新檔案會更容易一些。
ed -s file.txt <<-'EOF'
%s/^[[:space:]]*//
/customers {/ 1;/^[[:space:]]*}/w out.txt
%d
r out.txt
?{?;/^}/j
%s/^\([^\{]*\) \(.*\)$/\1\2 /
%j
s/^/thing1,/
s/ *$/,someting_else/
0a
product,customers,another_column
.
w output.csv
,p
Q
EOF
- 后者創建兩個檔案,
out.txt并且output.csv - 洗掉
,pif stdout 輸出不是必需的。
uj5u.com熱心網友回復:
輸入檔案在這里稱為“堆疊”。
#!/bin/sh -x
cat > ed1 <<EOF
/customers/
1
ka
$
-2
kb
'a,'bW output.txt
q
EOF
ed -s stack < ed1
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/513182.html
標籤:重击perlawksed
下一篇:如何使數字警告致命?
