Trong `sed`, làm cách nào tôi có thể đặt một & & giữa các ký tự trong một chuỗi?


11

Có thể sedlàm một cái gì đó như:

12345

trở nên :

1&2&3&4&5

?

Câu trả lời:


25

Với GNU sed:

sed 's/./\&&/2g'

( substolarship every ( g) character ( .) với cùng ( &) đứng trước &( \&) nhưng chỉ bắt đầu từ lần xuất hiện thứ hai ( 2)).

Có thể:

sed 's/./\&&/g;s/&//'

(thay thế mọi lần xuất hiện, nhưng sau đó xóa cái đầu tiên &mà chúng ta không muốn).

Với một số awktriển khai (không phải POSIX vì hành vi không được chỉ định cho một FS trống):

awk -F '' -v OFS="&" '{$1=$1;print}'

(cùng với gawkmột vài cách awktriển khai khác , một dấu tách trường trống sẽ phân tách các bản ghi thành các thành phần ký tự của nó . Dấu tách trường đầu ra ( OFS) được đặt thành &. Chúng tôi gán một giá trị cho $1(chính nó) để buộc bản ghi được tạo lại bằng dấu tách trường mới trước khi in, nó NF=NFcũng hoạt động và hiệu quả hơn một chút trong nhiều triển khai awk nhưng hành vi khi bạn làm điều đó hiện không được xác định bởi POSIX).

perl:

perl -F -lape '$_=join"&",@F' 

( -peChạy mã cho mỗi dòng, và in kết quả ( $_); -ldải và tái bổ sung kết thúc dòng tự động; -apopulates @Fvới chia đầu vào tập delimiter trong -F., Mà ở đây là một chuỗi rỗng Kết quả là chia mỗi nhân vật vào @F, sau đó nối chúng với '&' và in dòng.)

Cách khác:

perl -pe 's/(?<=.)./&$&/g' 

(thay thế mọi ký tự được cung cấp trước nó bởi một ký tự khác (toán tử regrec đằng sau (? <= ...))

Sử dụng zshtoán tử shell:

in=12345
out=${(j:&:)${(s::)in}}

(một lần nữa, phân tách trên một dấu tách trường trống bằng s::cờ mở rộng tham số và nối với &)

Hoặc là:

out=${in///&} out=${out#?}

(thay thế mọi sự cố không xảy ra (vì vậy trước mỗi ký tự) bằng &cách sử dụng ${var//pattern/replacement}toán tử ksh (mặc dù trong kshmột mẫu trống có nghĩa là một cái gì đó khác, và một cái gì đó khác, tôi không chắc chắn cái gì trong bash) và loại bỏ cái đầu tiên với ${var#pattern}tước POSIX nhà điều hành).

Sử dụng ksh93toán tử shell:

in=12345
out=${in//~(P:.(?=.))/\0&}

( ~(P:perl-like-RE)là toán tử toàn cầu ksh93 để sử dụng các biểu thức chính quy giống như perl (khác với perl's hoặc PCRE), (?=.)là toán tử nhìn về phía trước: thay thế một ký tự được cung cấp bởi một ký tự khác bằng chính nó ( \0) và &)

Hoặc là:

out=${in//?/&\0}; out=${out#?}

(thay thế mọi ký tự ( ?) bằng &và chính nó ( \0) và chúng tôi xóa ký tự thừa)

Sử dụng bashtoán tử shell:

shopt -s extglob
in=12345
out=${in//@()/&}; out=${out#?}

(giống như zsh's, ngoại trừ việc bạn cần @()có (một nhà điều hành ksh glob mà bạn cần extglobtrong bash)).


2
@AFSHIN, sẽ không hoạt động trên 012345đầu vào
Stéphane Chazelas

1
cái này sẽ hoạt độngawk -F '' -v OFS="&" 'NF=NF'
asнι

1
@AFSHIN, nhưng xóa các dòng trống. Tổng quát hơn, khi sử dụng một hành động làm điều kiện và dự định kết quả của hành động sẽ được in, bạn cần đảm bảo giá trị mà hành động trả về không phải là một chuỗi rỗng hoặc một chuỗi số có độ phân giải bằng 0.
Stéphane Chazelas

1
Bạn có thể thêm một lời giải thích nhanh về cách mỗi trong số này làm việc? Có vẻ như có một số điều tuyệt vời để tìm hiểu ở đây, nhưng tôi thậm chí không biết tôi bắt đầu nghiên cứu hầu hết chúng ở đâu để xem cách áp dụng chúng ngoài phạm vi của vấn đề cụ thể này.
IMSoP

1
@ StéphaneChazelas Rực rỡ, cảm ơn. Tìm kiếm các tài liệu phức tạp cho những thứ như sed là một nghệ thuật, vì vậy có một số ví dụ thực hành là một cách tuyệt vời để học các bit mới mà bạn chưa từng thấy trước đây.
IMSoP

15

Tiện ích Unix:

fold -w1|paste -sd\& -

Giải thích:

"fold -w1" - sẽ bọc một ký tự đầu vào vào dòng riêng của nó

gấp - bọc từng dòng đầu vào để phù hợp với chiều rộng quy định

-w, - thong = WIDTH sử dụng các cột WIDTH thay vì 80

%echo 12345|fold -w1
1
2
3
4
5

"paste -sd\& -"- sẽ hợp nhất các dòng đầu vào với nhau, sử dụng &như một dấu phân cách

dán - hợp nhất các dòng của tập tin

-s, --serial dán một tệp cùng một lúc thay vì song song

-d, --d006wr = LIST sử dụng lại các ký tự từ LIST thay vì TAB

%fold -w1|paste -sd\& -
1&2&3&4&5

(Lưu ý rằng nếu đầu vào chứa một vài dòng, chúng sẽ được nối với &)


2
Thất bại trên các nhân vật đa bào. Hãy thửecho "abcdeéèfg" | fold -1 | paste -sd\& -
Isaac

3
@Arrow Hầu hết có lẽ bạn chỉ sử dụng một lỗi coreutils phiên bản lần , mà không có một sự hỗ trợ Unicode đầy đủ. BSD gấp, các phiên bản RedHat vá của coreutils (tức là Fedora hoặc CentOS) cũng như thực hiện BusyBox của nó, có thể xử lý Unicode chỉ tốt đẹp.
zeppelin

5
Câu hỏi cụ thể là về sed.
Alexander

6
@Alexander - đó là sự thật, và có một số sedcâu trả lời tốt có sẵn dưới đây. Và tôi không thấy bất kỳ tác hại nào trong việc chứng minh làm thế nào nhiệm vụ có thể được giải quyết bằng các phương tiện khác.
zeppelin

@ StéphaneChazelas> POSIXly, bạn sẽ cần gấp -w 1 Đúng, tôi đã thêm "-w", thx! "-"lần lượt, không bắt buộc If no file operands are specified, the standard input shall be used
zeppelin


9
sed 's/\B/\&/g'

\ B - Phù hợp ở mọi nơi nhưng trên một ranh giới từ; đó là phù hợp nếu ký tự bên trái và ký tự bên phải là cả hai ký tự Từ trong một từ hoặc cả hai ký tự không chữ.

Thông tin: Hướng dẫn sử dụng GNU sed, phần mở rộng biểu thức chính quy .

Kiểm tra:

sed 's/\B/\&/g' <<< '12345'
1&2&3&4&5

5
Ý tưởng thú vị nhưng câu hỏi không nói rằng chuỗi không chứa khoảng trắng, dấu chấm hoặc bất cứ thứ gì có thể tạo thành một ranh giới từ. Nó chỉ nói "giữa các ký tự" nên được hiểu là "bất kỳ ký tự nào".
xhienne

4

Điều này sẽ chậm hơn một chút so với một số câu trả lời khác, nhưng nó khá rõ ràng:

echo 12345 | perl -lnE 'say join "&", split //'

4

Đây là một cách khác. Phần đầu tiên của biểu thức sed bắt giữ mọi nhân vật sau đó thay thế nó bằng ký tự và ký hiệu. Phần thứ hai loại bỏ ký hiệu và từ cuối dòng.

echo 12345 | sed -r 's/(.)/\1\&/g;s/\&$//g'
1&2&3&4&5

Hoạt động trên các nhân vật đa nhân cũng vậy.


1
Không cần phải gọi sedhai lần, một sedtập lệnh có thể có một số lệnh:sed -r 's/(.)/\1\&/g; s/\&$//g'
xhienne

xhienne, cảm ơn, TIL! Cập nhật câu trả lời.
Alexander
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.