Có phải là một cách tốt hơn để chỉ thay thế các dòng mới?


27

Tôi có thói quen viết một dòng trên mỗi câu vì tôi thường biên dịch mọi thứ cho LaTex hoặc đang viết ở một số định dạng khác trong đó ngắt dòng bị bỏ qua. Tôi sử dụng một dòng trống để chỉ sự bắt đầu của một đoạn mới.

Bây giờ, tôi có một tệp được viết theo phong cách này mà tôi muốn gửi dưới dạng văn bản thuần túy. Tôi muốn xóa tất cả các ngắt dòng đơn nhưng vẫn giữ nguyên các ngắt dòng kép. Đây là những gì tôi đã làm:

sed 's/$^/NEWLINE/' file.txt | awk '{printf "%s ",$0}' | sed 's/NEWLINE/\n\n/g' > linebreakfile.txt

Điều này thay thế các dòng trống bằng một số văn bản mà tôi tự tin không xuất hiện trong tệp: NEWLINEvà sau đó nó sẽ loại bỏ tất cả các ngắt dòng bằng awk (tôi đã tìm thấy mẹo đó trên một số trang web) và sau đó nó thay thế NEWLINEs bằng hai ngắt dòng cần thiết .

Đây có vẻ là một cách dài để làm một điều khá đơn giản. đó có phải là cách dễ hơn? Ngoài ra, nếu có một cách để thay thế nhiều không gian (đôi khi vì lý do nào đó) bằng các không gian duy nhất, điều đó cũng tốt.

Tôi sử dụng emacs, vì vậy nếu có một số thủ thuật cụ thể của emacs thì tốt, nhưng tôi muốn thấy một phiên bản sed thuần túy hoặc thuần túy.


Bạn có nghĩa là ^ $, không phải $ ^ trong lệnh sed đầu tiên.
người dùng không xác định

@user vâng, vâng tôi đã làm.
Seamus

Một cách dễ dàng hơn để loại bỏ tất cả các ngắt dòng : tr -d "\n".
jfg956

Câu trả lời:


18

Bạn có thể sử dụng awk như thế này:

$ awk ' /^$/ { print; } /./ { printf("%s ", $0); } ' test

Hoặc nếu bạn cần thêm một dòng mới vào cuối:

$ awk ' /^$/ { print; } /./ { printf("%s ", $0); } END { print ""; } ' test

Hoặc nếu bạn muốn tách các đoạn văn bằng một dòng mới:

$ awk ' /^$/ { print "\n"; } /./ { printf("%s ", $0); } END { print ""; } ' test

Các lệnh awk này sử dụng các hành động được bảo vệ bởi các mẫu:

/regex/

hoặc là

END

Một hành động sau chỉ được thực hiện nếu mẫu phù hợp với dòng hiện tại.

Và các ^$.ký tự có ý nghĩa đặc biệt trong các biểu thức chính quy, trong đó ^khớp với đầu dòng, $cuối và .một ký tự tùy ý.


Điều này là tốt, mặc dù tôi muốn giữ dòng trống giữa các đoạn. Tôi giả sử bạn có thể làm một cái gì đó như thế này bằng cách thêm một dòng mới ở đâu đó trong lệnh in đầu tiên? Ngoài ra, những gì đang /./làm: có vẻ như là hành động và elsecho /^$/chuỗi phù hợp, đúng không?
Seamus

1
@Seamus, chắc chắn - chỉ cần thay thế bản in đầu tiên (đã cập nhật câu trả lời) - /./ khớp với tất cả các dòng dài ít nhất một ký tự, tức là phần bù của mẫu / ^ $ / chỉ khớp với các dòng trống.
maxschlepzig

9

Sử dụng chế độ đoạn văn của Awk hoặc Perl để xử lý một đoạn tệp theo đoạn, trong đó các đoạn được phân tách bằng các dòng trống.

awk -vRS= '
  NR!=1 {print ""}      # print blank line before every record but the first
  {                     # do this for every record (i.e. paragraph):
    gsub(" *\n *"," "); # replace newlines by spaces, compressing spaces
    sub(" *$","");      # remove spaces at the end of the paragraph
    print
  }
'
perl -000 -pe '             # for every paragraph:
  print "\n" unless $.==1;  # print a blank line, except before the first paragraph
  s/ *\n *(?!$)/ /g;        # replace newlines by spaces, compressing spaces, but not at the end of the paragraph
  s/ *\n+\z/\n/             # normalize the last line end of the paragraph
'

Tất nhiên, vì điều này không phân tích cú pháp (La) TeX, nó sẽ cắt xén khủng khiếp các bình luận, môi trường nguyên văn và cú pháp đặc biệt khác. Bạn có thể muốn xem xét DeTeX hoặc các trình chuyển đổi TeX thành văn bản khác (La).


8

Giải pháp sed

$ sed -e ':a;N;$!ba;s/\(.\)\n/\1 /g' -e 's/\n/\n\n/' test.text

Lưu ý rằng trong giải pháp :anày là tạo nhãn và không sử dụng alệnh.

Thay thế nhiều không gian

Sử dụng tr:$ tr -s ' ' <test.text


8

Nếu tôi hiểu chính xác, một dòng trống có nghĩa là hai dòng mới liên tiếp , \n\n.

Nếu vậy, một giải pháp khả thi sẽ là loại bỏ tất cả các lần xuất hiện đơn lẻ của dòng mới.

Trong Perl, một khẳng định nhìn là một cách để đạt được điều này:

$ perl -0777 -i -pe 's/\n(?=[^\n])//g' test
  • Các -0777cờ hiệu quả slurps toàn bộ tập tin vào một chuỗi duy nhất
  • -p nói với perl để in chuỗi nó hoạt động theo mặc định
  • -i chỉ định chỉnh sửa tại chỗ
  • Kết hợp toàn cầu đảm bảo rằng tất cả các lần xuất hiện dòng mới đều được xử lý

Một vấn đề này là không có khoảng cách giữa các câu.
Steven D

6

(làm sống lại một câu hỏi cổ xưa)

Đây có vẻ là chính xác những gì fmtparđược dành cho - định dạng lại đoạn văn. Giống như bạn (và cũng giống như nhiều chương trình), họ xác định ranh giới đoạn là một (hoặc nhiều) dòng trống. Hãy thử đường ống văn bản của bạn thông qua một trong những điều này.

fmt là một tiện ích unix tiêu chuẩn và có thể được tìm thấy trong GNU Coreutils.

parlà một fmtbài viết được cải tiến rất nhiều bởi Adam M. Costello có thể tìm thấy tại http://www.nicemice.net/par/ (nó cũng đã được đóng gói cho một số bản phân phối, bao gồm cả debian - Tôi đã đóng gói nó cho debian vào tháng 1 năm 1996, mặc dù có một người duy trì mới cho pkg bây giờ.).


6
sed -e'/./{H;$!d;}' -e'x;s/\n//g'

sedsẽ nối bất kỳ dòng nào vào Hkhông gian cũ có chứa ít nhất một ký tự. Nó ngay lập tức trị liệu loại dbỏ tất cả những người ngoại trừ có lẽ cuối cùng. Các dòng duy nhất có thể còn lại là khoảng trắng, và nó nằm trên các dòng này khi sede xthay đổi khoảng cách giữ và mẫu và xóa tất cả các \nký tự ewline tích lũy .

Nếu bạn muốn các dòng chỉ chứa <tab> hoặc <dấu cách> được coi là trống, hãy thay thế /./địa chỉ trên bằng /[^[:blank:]]/. Để vắt kiệt không gian làm:

 sed -e'/./{H;$!d;}'    \
     -e'x;s/\n//g'      \
     -e's/\([[:blank:]]\)*/\1/g'

5

Sau khi xem các ví dụ nhỏ gọn của Gilles và awk, tôi đã miễn cưỡng đăng bài này, nhưng tôi đã trải qua bài tập, và đó là một kịch bản hoạt động, được ghi lại một cách hợp lý; điểm này một mình có thể được một số người quan tâm .. (sed với ý kiến! :)

Kịch bản lệnh này coi các dòng trống là trống ngay cả khi chúng chứa khoảng trắng.
Nhiều không gian trong văn bản được cô đọng thành một không gian duy nhất.
Khoảng trắng Trailing được loại bỏ khỏi các dòng văn bản. Các dòng trống liên tiếp được thu gọn thành một dòng duy nhất. Kịch bản để lại các dòng trống trên và dưới còn nguyên vẹn.

Đối với bất cứ điều gì nhiều hơn các tập lệnh tầm thường nhất, sed có thể được viết dễ dàng hơn nhiều trong một hình thức có cấu trúc, như một tệp tập lệnh riêng biệt. Đây là một ví dụ như vậy.

sử dụng cú pháp cú pháp regex mở rộng
: $ sed -rf script text-file

  :first-empty-line
  #================
  /^[[:space:]]*$/ { # if pattern-space is empty...
      $q  # last line # flush-quit 
      n   # pattern-flush=nextline-continue

      :subsequent-empty-line
      #=====================
      /^[[:space:]]*$/ { # if pattern-space is empty...
          $d        # last line # pattern-delete-cycle
          N         # pattern+=nl+nextline
          s/.*\n//  # scrap the leading 'blank' line
          t subsequent-empty-line # branch-on-substitute
      }
  }

  :text-line
  #=========
  $q                       # last line # flush-quit 
  s/^(.*)[[:space:]]*/\1/  # trim trailing whitespace
  s/ +/ /g                 # condense mulltiple spaces
  N                        # pattern+=nl+nextline
  /^.*\n[[:space:]]*$/ { # if newly-read line is blank 
      P          # pattern-first-line-print
      s/^.*\n//  # remove the leading 'text' line
      t first-empty-line   # branch-on-substitute
  }
  # read line is text
  s/\n/ /      # replace \n with a space
  t text-line  # branch-on-substitute

Lưu ý : flush, trong các ý kiến, có nghĩa là: gửi không gian mẫu để xử lý thiết bị xuất chuẩn nội bộ của sed. Nó không có nghĩa là một bản in xác định đến thiết bị xuất chuẩn. Đầu ra phụ thuộc vào -ntùy chọn của sed . ví dụ. các qlệnh phương tiện tuôn ra và bỏ ... Hãy so sánh hai đoạn sau đây: echo x |sed -e qin x, echo x |sed -ne qin gì cả, trong khi sử dụng các plệnh sẽ in 'x' hai lần hoặc một lần, tùy thuộc vào -ntùy chọn.


+1 cho ý kiến ​​tốt. Tôi đã xem quá nhiều chương trình mà không có bình luận nào cả.
David Cary

4

Đây là một sedgiải pháp khác ghép nối tất cả các dòng thành sed"không gian giữ" để chúng ta có được một chuỗi dài cuối cùng được sao chép vào "không gian mẫu" để khớp mẫu.

Vì các dòng mới sẽ được bảo tồn trong chuỗi dài cuối cùng trong sed"không gian mẫu" của 's, các dòng trống về mặt ngắt dòng kép [^\n]\n\n[^\n]có thể được khớp và sửa đổi thành [^\n]\n[^\n].

Để biết thêm thông tin, hãy xem, ví dụ, sed và Tìm kiếm và Thay thế nhiều dòng .

text='
line 1

line 2
line 3





line 4


line     5



line 6
line 7

line 8
'

# FreeBSD sed
# first sed deletes first / last line if empty and squeezes multiple spaces
printf '%s' "$text" |
sed -e '1{/^$/d;}' -e '${/^$/d;}' -e '/[[:space:]]\{2,\}/s// /g' | 
sed -n -e '1h;1!H;${;g;/\([^[:cntrl:]]\)\n\n\([^[:cntrl:]]\)/s//\1\
\2/g;p;}' |
nl -b a


# GNU sed
# alternative using ...;x;... instead of ...;g;...
# cf. man sed | less -p '\]x'
printf '%s' "$text" |
gsed -e '1{/^$/d;}' -e '${/^$/d;}' -e '/[[:space:]]\{2,\}/s// /g' | 
gsed -E -n '1h;1!H;${;x;/([^\n])\n\n([^\n])/s//\1\
\2/g;p;}' | 
nl -b a


# remove all the single linebreaks but leave the double linebreaks intact
printf '%s' "$text" | 
   sed -n -e '1h;1!H;${;g;/\([^[:cntrl:]]\)\n\([^[:cntrl:]]\)/s//\1 \2/g;p;}' | 
   nl -b a

3

Đây có thể là trường học cũ:

(echo ".pl 1" ; echo ".ll 80" ; echo ".ad l" ; cat your_file) | nroff

Điều này sẽ xuất văn bản của bạn được căn trái ( .ad l), với độ dài dòng là 80 ( .ll 80). Tùy chọn độ dài trang ( .pl) cho bộ xử lý văn bản thực hiện đệm trang cho độ dài trang là 1, do đó không có đệm trang.

Nếu bạn muốn tất cả các đoạn của mình trên một dòng, bạn có thể sử dụng một số lượng lớn cho .ll:

(echo ".pl 1" ; echo ".ll 1000000" ; echo ".ad l" ; cat your_file) | nroff

man 7 groff cho nhiều tùy chọn định dạng.


1

Trong Emacs, đôi khi tôi sử dụng điều này regex:

^J\([^^J]\) -> \1

Có nghĩa:

thay thế mọi dòng mới được theo sau bởi một cái gì đó KHÔNG phải là một dòng mới chỉ với thứ đó, theo dòng mới đó theo cách đó tôi thoát khỏi tất cả các dòng mới trong một đoạn nhưng giữ các đoạn (hai dòng mới)


0

Hóa ra là với auto-fill-mode, emacs làm rất tốt cho các trường hợp sử dụng đơn giản của tôi chỉ với M-q...


Các chi tiết về những gì auto-fill-modekhông phụ thuộc vào chế độ chính mà bạn đã kích hoạt.
dmckee
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.