Làm cách nào để hợp nhất văn bản của các dòng chữ cái với các dòng số trong shell?


10

Tôi có một tập tin có văn bản như thế này:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

Vân vân...

Và tôi muốn ghép các dòng chữ cái với các dòng Số để chúng giống như thế này:

AAAA 1234 
BBBB 5678
CCCC 9012
DDDD 3456

EEEE 7890

Có ai biết một cách đơn giản để đạt được điều này?


Bạn đề cập đến emacs.. Bạn đang tìm kiếm một elispgiải pháp, hoặc làm thế nào để chạy shell-script từ bên trong emacs?
Peter.O

Câu trả lời:


3

Một cách sử dụng perl:

Nội dung của script.pl:

use warnings;
use strict;

## Check arguments.
die qq[Usage: perl $0 <input-file>\n] unless @ARGV == 1;

my (@alpha, @digit);

while ( <> ) {
        ## Omit blank lines.
        next if m/\A\s*\Z/;

        ## Remove leading and trailing spaces.
        s/\A\s*//;
        s/\s*\Z//;

        ## Save alphanumeric fields and fields with
        ## only digits to different arrays.
        if ( m/\A[[:alpha:]]+\Z/ ) {
                push @alpha, $_;
        }
        elsif ( m/\A[[:digit:]]+\Z/ ) {
                push @digit, $_;
        }
}

## Get same positions from both arrays and print them
## in the same line.
for my $i ( 0 .. $#alpha ) {
        printf qq[%s %s\n], $alpha[ $i ], $digit[ $i ];
}

Nội dung của infile:

AAAA
BBBB
CCCC
DDDD

1234
5678
9012
3456

EEEE 

7890

Chạy nó như:

perl script.pl infile

Và kết quả:

AAAA 1234
BBBB 5678
CCCC 9012
DDDD 3456
EEEE 7890

Thú vị ... Hai dòng thay thế regex của bạn Loại bỏ khoảng trắng hàng đầu và dấu kiểm chạy nhanh hơn khoảng 1,6 lần so với một dòng sử dụng phản hồi ngược và không tham lam : s/\A\s*(.*?)\s*\Z/\1/.
Peter.O

4

Trong awk, bảo quản các dòng trống, giả sử tệp được định dạng tốt, nhưng logic có thể được thêm vào để kiểm tra tệp:

awk -v RS="" '{for(i=1; i<=NF; i++) a[i]=$i
  getline
  for(i=1; i<=NF; i++) print a[i] " " $i
  print ""}' file

4
<input sed -nr '/^[A-Z]{4}$/,/^$/w out1
                /^[0-9]{4}$/,/^$/w out2'
paste -d' ' out1 out2 |sed 's/^ $//' 

hoặc, trong một bước duy nhất, không có tệp tạm thời

paste -d' ' <(sed -nr '/^[A-Z]{4}$/,/^$/p' input) \
            <(sed -nr '/^[0-9]{4}$/,/^$/p' input) | sed 's/^ $//' 

Bước cuối cùng sedloại bỏ dấu phân cách trên các dòng trống, được giới thiệu bởi paste...


3

Với emacs sử dụng các thao tác hình chữ nhật để cắt các dòng văn bản và dán chúng trước các dòng số.


Cảm ơn, nhưng không thực sự phù hợp với hơn 15000 dòng! + 1 cho một ý tưởng làm việc và bạn cần người đại diện :)
NWS

2

Nếu các mục theo thứ tự,

  1. Chia đầu vào thành các mục nhập chữ cái và số, sử dụng grep:

    • grep "[[:alpha:]]\+" < file > alpha
    • grep "[[:digit:]]\+" < file > digit
  2. Tham gia hai tệp kết quả alphadigitsử dụng paste:

    • paste alpha digit(bạn có thể thêm -d " "để nó sử dụng khoảng trắng thay vì tab)

1
Không có tệp tạm thời: paste <(grep "[[:alpha:]]\+" file) <(grep "[[:digit:]]\+" file)hoặc với một thay thế quá trình duy nhất : grep "[[:alpha:]]\+" file | paste - <(grep "[[:digit:]]\+" file).
jfg956

1

Quá tệ awk không có chức năng đẩy / pop / unshift / shift đẹp. Đây là một đoạn ngắn Perl

perl -M5.010 -lne '
  given ($_) {
    when (/^[[:alpha:]]+$/) {push @alpha, $_}
    when (/^\d+$/) {say shift(@alpha), " ", $_}
    default {say}
  }
'

Khi tôi chạy nó, nó xuất ra một dòng trống bổ sung (hàng đầu) cho mỗi nhóm.
Peter.O

Do defaultmệnh đề, các dòng trống được in ngay lập tức, do đó khoảng trống trước "1234" sẽ hiển thị trước dòng "AAAA".
glenn jackman

0

Cung cấp tệp có văn bản, thử sử dụng prvà xử lý cú pháp thay thế như dưới đây:

$ pr -mt <(grep -i "^[a-z]" file.txt) <(grep -i "^[0-9]" file.txt)
AAAA                    1234
BBBB                    5678
CCCC                    9012
DDDD                    3456
EEEE                    7890

Bạn có thể điều chỉnh chiều rộng bằng -w9hoặc loại bỏ khoảng trắng bằng sed "s/ //g".

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.