Thay thế chuỗi trong một tệp rất lớn


10

Tôi có một chuỗi các url rất dài không có ký tự phân tách, có cùng định dạng như dưới đây:

http://example.comhttp://example.nethttp://example.orghttp://etc...

Tôi muốn mỗi URL nằm trên một dòng mới. Tôi đã cố gắng thực hiện điều này bằng cách thay thế tất cả các phiên bản của "http: //" bằng "\ nhttp: //" bằng cách sử dụng sed

sed 's_http://_\nhttp://_g' urls.txt

nhưng xảy ra lỗi phân đoạn (vi phạm bộ nhớ). Tôi chỉ có thể phỏng đoán rằng kích thước tuyệt đối của tệp (trên 100 GB) đang khiến sed vượt quá giới hạn.

Tôi có thể chia tệp thành nhiều tệp nhỏ hơn để xử lý, nhưng tất cả các phiên bản của "http: //" sẽ cần được giữ nguyên.

Có cách nào tốt hơn để làm điều này?


Tôi nghĩ rằng sed không thích 100GB mà không có kết thúc dòng vì nó cố đọc một dòng trong bộ đệm của nó.
jippie

tách (không phân biệt "nơi" xảy ra cắt), xử lý, sau đó tập hợp lại sẽ cho kết quả chính xác.
enzotib

3
Nếu bạn thực sự có một tệp văn bản 100 GB chứa một dòng dài, thì tốt hơn hết bạn nên viết một chương trình C nhanh để thực hiện công việc.
fpmurphy

Câu trả lời:


11

Với awkbạn có thể tránh đọc số lượng lớn văn bản cùng một lúc:

awk -vRS='http://' -vORS='\nhttp://' 1 urls.txt > urlsperline.txt

Sự thành công có thể phụ thuộc vào việc awkthực hiện được sử dụng . Ví dụ gawkhoạt động tốt, nhưng mawksự cố.


6

Điều này sẽ làm công việc:

perl -pe 'BEGIN { $/ = "//" } s!(?=http://\z)!\n!' urls.txt

Bằng cách đặt $ / , tôi đã thay đổi định nghĩa của một dòng để nó kết thúc bằng //thay vì một dòng mới. Điều này làm cho Perl đọc một URL mỗi lần. Không chắc là URL chứa //ngoại trừ sau lược đồ, nhưng nếu có, URL sẽ không cho phép thêm các dòng mới giả.

Nếu bạn muốn tránh thêm một dòng trống trước URL đầu tiên:

perl -pe 'BEGIN { $/ = "//"; print scalar <> } s!(?=http://\z)!\n!' urls.txt

Bạn có thể thử điểm chuẩn để xem có s!http://\z!\nhttp://!nhanh hơn không. Chúng tương đương nhau. Lưu ý rằng /gcờ không cần thiết cho sự thay thế, bởi vì chỉ có thể có một trận đấu trên mỗi "dòng".


Công cụ regrec perl có ổn với các dòng dài nhiều gigabyte không?
Alexios

2
@Alexios, có lẽ là không, nhưng nó không cần phải như vậy. Vì tôi đã thay đổi $/, nên mỗi lần chỉ xử lý một URL.
cjm

Ah, tôi thấy những gì bạn đã làm ở đó. Đã được một thời gian kể từ những năm 90, và tôi đã phải man perlvar, nhưng nó có ý nghĩa như vậy.
Alexios

Linux cho phép các url có nhúng nhiều dấu gạch chéo trong các đường dẫn, vì vậy mã này có thể thất bại nếu bạn có bất kỳ dấu nào trong số đó. Kiểm tra toàn bộ chuỗi, http và tất cả, sẽ không có vấn đề này.
Joe

@Joe, tôi đang thử nghiệm cho http:phần trong regex. Nó sẽ kiểm tra mọi thứ //, nhưng nó sẽ không thêm một dòng mới trừ khi nó tìm thấy http://.
cjm

5
  1. Thay đổi tất cả các lần xuất hiện của a :với một dòng mới, để cắt tập tin.
  2. Thay thế
    • http ở cuối dòng với
    • một dòng mới theo sau http:và nối dòng tiếp theo với nó
  3. Lặp lại một lần, do đó, các dòng chẵn và lẻ được cập nhật

Các bước này trông giống như:

tr ':' '\n' | sed -e '/http$/{N;s/http\n/\nhttp:/}' | sed -e '/http$/{N;s/http\n/\nhttp:/}'
  1. Kiểm tra xem có dòng nào không bắt đầu không http://, in số dòng. Điều này sẽ chỉ xảy ra nếu a: ở đâu đó trong URL khác sau http.

    grep -nv '^http://'

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.