Làm cách nào để tôi chèn một khoảng trắng cứ bốn ký tự trong một hàng dài?


30

Tôi đã có một dòng dài mà tôi muốn chèn một khoảng trắng cứ sau 4 ký tự, trên một dòng văn bản đơn lẻ để dễ đọc hơn, cách đơn giản nhất để làm điều này là gì? Ngoài ra tôi sẽ có thể nhập dòng từ một đường ống. ví dụ

echo "foobarbazblargblurg" | <some command here>

cho

foob arba zbla rgbl urg

Câu trả lời:


54

Sử dụng sed như sau:

$ echo "foobarbazblargblurg" | sed 's/.\{4\}/& /g'
foob arba zbla rgbl urg

1
chửi rủa rất gần với sedtôi đã thử trước tiên tôi có thể tự đá mình.
xenoterracide

7
Chỉ tò mò, những gì '&' hoàn thành? Ồ, đó là một ý kiến ​​cho "thứ vừa khớp". Tôi ngớ ngẩn quá.
Omnifarious

1
cần lưu ý rằng điều này cũng thêm một khoảng trống ở cuối nếu có thêm một ký tự trong chuỗi, điều này có thể không được mong muốn
Anubis

@ Anubis's/.\{4\}/& /g;s/ $//'
wieczorek1990

20

Bạn có thể sử dụng ví dụ đơn giản sau:

$ echo "foobarbazblargblurg" | fold -w4 | paste -sd' ' -
foob arba zbla rgbl

Rất đẹp ... Tôi nghĩ điều này thậm chí còn tốt hơn sedcâu trả lời. Tôi đã không biết về foldtrước đây.
tự đại diện

1
Thật không may, với các phiên bản hiện tại của GNU fold, nó không hoạt động với các ký tự nhiều byte (như echo €€€€€€€€ | fold -w4 | paste -sd' ' -trong UTF-8).
Stéphane Chazelas

3

Dưới đây là ví dụ sử dụng grepxargs:

$ echo "foobarbazblargblurg" | grep -o .... | xargs
foob arba zbla rgbl

xargschạy echotheo mặc định, do đó, nó sẽ không hoạt động với các từ như -nenhoặc có chứa dấu gạch chéo ngược tùy thuộc vào việc echotriển khai. Thỉnh thoảng bạn cũng sẽ thấy nhân vật dòng mới lẻ nếu xargs chạy nhiều hơn một echo. Tốt hơn để đường ống để paste -sd ' ' -thay thế. Lưu ý rằng đó -okhông phải là một lựa chọn tiêu chuẩn.
Stéphane Chazelas

3

Chỉ trong bash, không có lệnh bên ngoài:

str="foobarbazblargblurg"
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"

hoặc là phiên bản ống một dòng:

echo foobarbazblargblurg | 
  { IFS= read -r str; [[ $str =~ ${str//?/(.)} ]]; \
    printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"; }

Cách thức hoạt động này là chuyển đổi từng ký tự của chuỗi thành "(.)" Để khớp regex và chụp với =~, sau đó chỉ xuất các biểu thức đã chụp từ BASH_REMATCH[]mảng, được nhóm theo yêu cầu. Không gian hàng đầu / dấu / trung gian được giữ nguyên, loại bỏ các trích dẫn xung quanh "${BASH_REMATCH[@]:1}"để bỏ qua chúng.

Ở đây, nó được gói trong một hàm, cái này sẽ xử lý các đối số của nó hoặc đọc stdin nếu không có đối số:

function fmt4() {
  while IFS= read -r str; do
    [[ $str =~ ${str//?/(.)} ]]
    printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
  done < <( (( $# )) && printf '%s\n' "$@" || printf '%s\n' $(< /dev/stdin) )
}

$ echo foobarbazblargblurg | fmt4
foob arba zbla rgbl urg 

Bạn có thể dễ dàng tham số đếm để điều chỉnh chuỗi định dạng cho phù hợp.

Một không gian dấu được thêm vào, sử dụng hai printfs thay vì một nếu đó là một vấn đề:

printf "%s%s%s%s" "${BASH_REMATCH[@]:1:4}"
(( ${#BASH_REMATCH[@]} > 5 )) && printf " %s%s%s%s" "${BASH_REMATCH[@]:5}"

Bản printfin đầu tiên (tối đa) 4 ký tự đầu tiên, bản thứ hai có điều kiện in tất cả phần còn lại (nếu có) với khoảng trắng ở đầu để phân tách các nhóm. Bài kiểm tra dành cho 5 phần tử chứ không phải 4 để tính phần tử zeroth.

Ghi chú:

  • vỏ printf's %ccó thể được sử dụng thay cho %s, %c(có thể) làm cho mục đích rõ ràng hơn, nhưng nó không phải là đa byte nhân vật an toàn. Nếu phiên bản bash của bạn có khả năng, thì trên đây là tất cả các ký tự nhiều byte an toàn.
  • shell printfsử dụng lại chuỗi định dạng của nó cho đến khi hết các đối số, do đó, nó chỉ cần xử lý 4 đối số cùng một lúc và xử lý các đối số theo sau (vì vậy không có trường hợp cạnh nào cần thiết, không giống như một số câu trả lời khác ở đây có thể được cho là sai)
  • BASH_REMATCH[0] là toàn bộ chuỗi khớp, vì vậy chỉ có đầu ra bắt đầu từ chỉ mục 1
  • printf -v myvar ...thay vào đó sử dụng để lưu trữ vào một biến myvar(theo hành vi vòng lặp đọc / chuỗi con thông thường)
  • thêm printf "\n"nếu cần

Bạn có thể làm cho các công việc trên hoạt động zshnếu bạn sử dụng mảng match[]thay vì BASH_REMATCH[]và trừ 1 khỏi tất cả các chỉ mục vì zshkhông giữ nguyên phần tử 0 với toàn bộ kết quả khớp.


3

Chỉ với zsh:

str=foobarbazblargblurg

set -o extendedglob
printf '%s\n' ${str//(#m)????/$MATCH }

Hoặc là

printf '%s%s%s%s ' ${(s::)str}

ksh93chỉ với :

printf '%s\n' "${str//????/\0 }"

Chỉ với bất kỳ vỏ POSIX nào (cũng tránh không gian dấu nếu độ dài đầu vào là bội số của 4):

out=
while true; do
  case $str in
    (?????*)
      new_str=${str#????}
      out=$out${str%"$new_str"}' '
      str=$new_str
      ;;
    (*)
      out=$out$str
      break
  esac
done
printf '%s\n' "$out"

Bây giờ, đó là cho các nhân vật . Nếu bạn muốn làm điều đó trên các cụm grapheme (ví dụ: để ngắt Stéphane, được viết là $'Ste\u0301phane', như Stép hanevà không Ste phan e), với zsh:

set -o rematchpcre
str=$'Ste\u301phane' out=
while [[ $str =~ '(\X{4})(.+)' ]] {
  out+="$match[1] " str=$match[2]
}
out+=$str
printf '%s\n' $out

Với ksh93, bạn cũng có thể phá vỡ bằng chiều rộng hiển thị, điều này sẽ hoạt động cho điều đó Stéphaneở trên, nhưng cũng có thể giúp ích khi một số loại ký tự có độ rộng bằng không hoặc chiều rộng gấp đôi khác có liên quan:

str=$'Ste\u301phane' out=
while
  start=${ printf %L.4s. "$str"; }
  start=${start%.}
  [ "$start" != "$str" ]
do
  out+="$start " str=${str#"$start"}
done
out+=$str
printf '%s\n' "$out"

2

Tôi sẽ trả lời bằng cách chỉ chèn khoảng trắng theo yêu cầu để một khoảng trắng xuất hiện ít nhất sau mỗi 4 ký tự trên một dòng; không chắc chắn cách bạn muốn xử lý trường hợp này. Ví dụ: đầu vào đã cho của "aa bbccdd", bạn sẽ nhận được đầu ra "aa bbcc dd" thay vì "aa b bccd d".

Tôi đang sử dụng Perl cho lookahead, nhưng nói chung tôi không quen thuộc lắm với Perl, vì vậy có thể có các điều chỉnh cần thiết:

$ echo "foobarbazblargblurg" | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
foob arba zbla rgbl urg

$ echo 'aa bbccdd' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
aa bbcc dd
# not 'aa b bccd d'!

$ echo 'some input' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
some inpu t
# not 'some  inp ut'!

$ echo $'aabb\nc cddee' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g' | 
> while read; do echo "${REPLY}x"; done
aabbx
c cdde ex
# no spaces added at the end of the first line (while loop to add to the end of
# the line and show this)

0

Tôi đã làm điều này bằng cách sử dụng python

Đầu tiên tôi đang đọc tập tin sau đó tôi chia cho 4 ký tự và thêm khoảng trắng

#!/usr/bin/python
import re
b=re.compile(r'[a-z]{4}')

p=open('/root/l.txt','r')
i=p.readlines()
for j in i:
    m=re.findall(b,j)
print " " .join (m) + "  "

/root/l.txt ==> Bao gồm nội dung mà bạn đã đưa ra trong ví dụ

đầu ra

foob arba zbla rgbl
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.