2010-03-18 60 views
8

Tôi có trường hợp sử dụng này của một tập tin xml với đầu vào nhưKết hợp nhiều dòng vào một dòng

Input: 
<abc a="1"> 
    <val>0.25</val> 
</abc> 
<abc a="2"> 
    <val>0.25</val> 
</abc> 
<abc a="3"> 
    <val>0.35</val> 
</abc> 
... 

Output: 
<abc a="1"><val>0.25</val></abc> 
<abc a="2"><val>0.25</val></abc> 
<abc a="3"><val>0.35</val></abc> 

tôi có khoảng 200K dòng trong một tập tin theo định dạng đầu vào, làm thế nào tôi có thể nhanh chóng chuyển đổi này sang định dạng đầu ra .

Trả lời

3

Trong vim bạn có thể làm điều này với

:g/<abc/ .,/<\/abc/ join! 

thường: tham gia sẽ thêm một không gian tại kết thúc của mỗi dòng trước khi tham gia, nhưng ! ngăn chặn điều đó. Nói chung, tôi khuyên bạn nên sử dụng một thư viện phân tích cú pháp XML thích hợp trong một ngôn ngữ như Python, Ruby hoặc Perl để thao tác các tệp XML (tôi khuyên dùng Python + ElementTree), nhưng trong trường hợp này, nó đủ đơn giản để tránh sử dụng giải pháp regex.

+0

Cảm ơn bạn! Đây chính xác là những gì tôi cần! –

+0

Tôi có một giải pháp tương tự, chỉ vì nó sẽ giữ khoảng cách giữa> và < ': g/val/norm kJxJx' nhưng nếu bạn không quan tâm đến điều đó chỉ cần thực hiện: ' g/val/norm kJJ' – SergioAraujo

0

inlegant perl one-liner mà nên làm các trick, mặc dù không phải đặc biệt nhanh chóng.

cat file | perl -e ' 
    $x=0; 
    while(<>){ 
     s/^\s*(\S*(?:\s+\S+)*)\s*$/$1/g; 
     print; 
     $x++; 
    if($x==3){ 
     print"\n"; 
     $x=0; 
    } 
}' > output 
+0

Thay vì 'cat file', chỉ cần sử dụng' Arkku

+0

@Arkku - cũng sẽ hoạt động. Đó là thói quen cũ của tôi, và tôi thấy thoải mái hơn với con mèo $ FILE | – zellio

+0

Mặc dù vậy, nó bắn ra một 'con mèo' vô dụng. Trên một số hệ thống bị hạn chế cao, có giới hạn thấp về số lượng các quá trình đồng thời mà nó được tính vào. Ngoài ra, nó có thể là một sự suy giảm đáng kể nếu quá trình đó là một trình đọc nhanh, ví dụ: thử 'cat/dev/zero | dd bs = 1k count = 1000' so với 'dd bs = 1k count = 1000 Arkku

0

Bạn có thể làm điều này:

perl -e '$i=1; while(<>){chomp;$s.=$_;if($i%3==0){$s=~s{>\s+<}{><};print "$s\n";$s="";}$i++;}' file 
+0

chomp là không tốt bởi vì nó để lại đằng sau quá nhiều khoảng trắng, trừ khi người hỏi của chúng tôi là okay với điều đó. – zellio

+0

@Mimisbrunnr: nếu bạn nhìn kỹ, tôi sử dụng regex để loại bỏ các khoảng trống thừa. – codaddict

+0

Tôi xin lỗi, tôi đã nói trước khi đọc đầy đủ mã của bạn. – zellio

1
$ awk ' 
    /<abc/ && NR > 1 {print ""} 
    {gsub(" +"," "); printf "%s",$0} 
' file 
<abc a="1"> <val>0.25</val></abc> 
<abc a="2"> <val>0.25</val></abc> 
<abc a="3"> <val>0.35</val></abc> 
+0

+1 Bạn cũng sẽ muốn: 'END {print" "}' để đảm bảo tệp kết thúc bằng một dòng mới. –

0
sed '/<abc/,/<\/abc>/{:a;N;s/\n//g;s|<\/abc>|<\/abc>\n|g;H;ta}' file 
0
tr "\n" " "<myfile|sed 's|<\/abc>|<\/abc>\n|g;s/[ \t]*<abc/<abc/g;s/>[ \t]*</></g' 
1

Bash:

while read s; do echo -n $s; read s; echo -n $s; read s; echo $s; done < file.xml 
1

Bạn có thể ghi một macro. Về cơ bản những gì tôi sẽ làm là bắt đầu với con trỏ của tôi ở đầu dòng đầu tiên. Nhấn 'qa' (ghi macro vào thanh ghi). Nhấn shift-V để trở thành chế độ hiển thị trực quan. Sau đó tìm kiếm thẻ kết thúc '// abc'. Sau đó nhấn shift-J để tham gia các dòng. Sau đó, bạn sẽ phải di chuyển con trỏ đến thẻ tiếp theo, có thể với 'j ^' và nhấn 'q' để dừng ghi. Sau đó, bạn có thể chạy lại bản ghi bằng '@a' hoặc chỉ định 10000 @ a nếu bạn muốn. Nếu các thẻ khác nhau hoặc không phù hợp với nhau, bạn chỉ cần thay đổi cách bạn tìm thẻ mở và đóng để tìm kiếm hoặc một cái gì đó tương tự.

+0

Rõ ràng đây là giải pháp dựa trên vim ... –

4

Trong Vim:

  • vị trí trên dòng đầu tiên
  • qq: bắt đầu ghi vĩ mô
  • gJgJ: tham gia hai dòng tiếp theo mà không gian thêm
  • j: đi xuống
  • q: stop ghi âm
  • [email protected]: N = Số dòng (trên thực tế khoảng 1/3 của tất cả các dòng như họ nhận được ngưng tụ trên đường đi)
+0

Sau 'gJgJ', không cần thiết cho' j'. – systemovich

0

này nên làm việc trong chế độ cũ:

:%s/\(^<abc.*>\)^M^\(.*\)^M^\(^<\/abc>\).*^M/\1\2\3^M/g

tôi nên có thêm dấu cách (hoặc một tab ở giữa giá trị), nhưng bạn coud loại bỏ nó tùy thuộc vào nó là gì (\ t hoặc \ \ \ \).

gì bạn đang tìm kiếm/thay thế được ở đây là (pattern1) [nhập] (pattern2) [nhập] (pattern3) [nhập] và thay thế nó bằng (pattern1) (pattern2) (pattern3) [nhập]

^M được thực hiện với ctrl + v CTRL + m

1
sed '/^<abc/{N;N;s/\n\| //g}' 

# remove \n or "space" 
# Result 

<abca="1"><val>0.25</val></abc> 
<abca="2"><val>0.25</val></abc> 
<abca="3"><val>0.35</val></abc> 
Các vấn đề liên quan