2009-06-05 29 views
9

Tôi đang cố gắng tạo một hệ thống gói từ lỏng lẻo qua một regex trong Perl. Những gì tôi muốn là về mỗi 70 ký tự hoặc như vậy để kiểm tra sự xuất hiện khoảng trắng tiếp theo và thay thế không gian đó bằng một dòng mới, và sau đó làm điều này cho toàn bộ chuỗi. Chuỗi tôi đang hoạt động trên có thể đã có dòng mới trong nó, nhưng số lượng văn bản giữa các dòng mới có xu hướng rất dài.Làm thế nào tôi có thể bọc một chuỗi trong Perl?

Tôi muốn tránh lặp một ký tự tại một thời điểm hoặc sử dụng substr nếu tôi có thể, và tôi muốn chỉnh sửa chuỗi này ở vị trí như trái ngược với tạo các đối tượng chuỗi mới. Đây chỉ là những ưu tiên, và nếu tôi không thể đạt được những gì tôi đang tìm kiếm mà không vi phạm những ưu đãi này thì điều đó là tốt.

Suy nghĩ?

+1

Thay vì khoảng trắng, có một bộ ký tự biểu hiện bằng \ b phù hợp với ranh giới từ đó có thể mạnh mẽ hơn một chút. – jiggy

+2

@jiggy \ b không phải là một lớp nhân vật, đó là xác nhận 0 độ rộng. –

+2

Bên cạnh đó, "nhấn mạnh!"có thể phá vỡ giữa các từ một dấu câu, và đó chỉ là sai ! – Axeman

Trả lời

11
s/(.{70}[^\s]*)\s+/$1\n/ 

Tiêu thụ 70 ký tự đầu tiên, sau đó dừng lại ở khoảng trắng tiếp theo, chụp mọi thứ trong quá trình. Sau đó, phát ra chuỗi đã thu thập, bỏ qua khoảng trắng ở cuối, thêm một dòng mới.

này không đảm bảo dòng của bạn sẽ cắt đứt hoàn toàn ở 80 ký tự hoặc một cái gì đó. Không có gì đảm bảo rằng từ cuối cùng nó tiêu thụ sẽ không phải là một tỷ ký tự.

+1

Tôi nghĩ rằng sẽ tốt hơn. {70,80} \ s +, để nếu bạn nhận được" như trong một "bắt đầu với không gian ở 71, – Axeman

+0

@Axeman là chính xác, nhưng nhờ đánh giá tham lam (mà cố gắng để phù hợp với càng nhiều nội dung càng tốt), bạn muốn. {1,70} cho một chiều dài dòng 70. Tôi đã chỉnh sửa câu trả lời –

+1

Regexp nâng cao hơn, có thể xử lý một cách duyên dáng các ngắt dòng (thay vì giết chúng như là ví dụ trên cơ bản) sẽ là 's/(. {1,70} | \ S {71,}) (?: \ s [^ \ S \ r \ n] * | \ Z)/$ 1 \ n/g'. Tôi muốn giữ câu trả lời chính thức đơn giản, vì vậy tôi đã bỏ nó ra. –

22

Nhìn vào mô-đun như Text::Wrap hoặc Text::Autoformat.

Tùy thuộc vào nhu cầu của bạn, ngay cả những GNU tiện ích lõi lần (1) có thể là một lựa chọn.

+1

Đó có lẽ là cách tốt nhất - ngoại trừ một số – Axeman

+0

Thực ra tôi chỉ thấy rằng Text :: Wrap :: Smart dừng phá vỡ một dòng nếu có một từ longe r hơn kích thước thông báo được xác định. – RushPL

7

Welbog của câu trả lời kết thúc tốt đẹp tại không gian đầu tiên sau 70 ký tự. Điều này có lỗ hổng mà từ dài bắt đầu gần cuối dòng tạo ra một đường quá dài. Thay vào đó, tôi sẽ đề nghị thay thế không gian cuối cùng trong vòng đầu tiên, ví dụ: 81 ký tự hoặc gói ở khoảng trống đầu tiên nếu bạn có từ> 80 ký tự ", vì vậy chỉ có các dòng không thể phá vỡ thực sự là quá dài:

s/(.{1,79}\S|\S+)\s+/$1\n/g; 

Trong perl hiện đại:

s/(?:.{1,79}\S|\S+)\K\s+/\n/g; 
+1

D'oh! Và tôi thậm chí đã làm điều này nhiều lần. – Axeman

5

Bạn có thể nhận được quyền kiểm soát nhiều, nhiều hơn nữa và độ tin cậy bằng cách sử dụng Text::Format

use Text::Format; 
print Text::Format->new({columns => 70})->format($text); 
1

Đây là một trong những tôi đã luôn luôn được sử dụng.

Không giống như giải pháp được chấp nhận, nó sẽ bọc TRƯỚC KHI chiều dài quấn (trong trường hợp này là 75 ký tự), trừ khi có chuỗi dài thực sự (chẳng hạn như URL). dòng riêng, thay vì phá vỡ nó.

s/(?=.{70,})(.{0,70}\n?)()/\1\2\n /g 

hình thức thứ hai này xử lý tất cả kết thúc dòng: Mac \ r, Unix \ n, Windows \ r \ n, và Teletype \ n \ r, nhưng cái nào nó sử dụng như một sự thay thế vẫn còn phụ thuộc vào những gì bạn đưa trong mệnh đề thay thế: Tôi đã sử dụng \ n.

s/(?=.{70,})(.{0,70}(?:\r\n?|\n\r?)?)()/\1\2\n /g 

Cả hai phiên bản đều thụt lề tất cả các dòng được bao bọc trước tiên/g nếu bạn không muốn, nhưng tôi thường thấy nó đẹp hơn.

Các vấn đề liên quan