Làm thế nào để trích xuất văn bản từ một chuỗi bằng cách sử dụng sed?


95

Chuỗi ví dụ của tôi như sau:

This is 02G05 a test string 20-Jul-2012

Bây giờ từ chuỗi trên tôi muốn trích xuất 02G05. Đối với điều đó, tôi đã thử regex sau đây với sed

$ echo "This is 02G05 a test string 20-Jul-2012" | sed -n '/\d+G\d+/p'

Nhưng lệnh trên không in ra gì và lý do tôi tin là nó không thể khớp bất cứ thứ gì với mẫu tôi đã cung cấp cho sed.

Vì vậy, câu hỏi của tôi là tôi đang làm gì sai ở đây và làm thế nào để sửa nó.

Khi tôi thử chuỗi và mẫu ở trên với python, tôi nhận được kết quả của mình

>>> re.findall(r'\d+G\d+',st)
['02G05']
>>>

6
Python chắc chắn là không sed. Hương vị regex của chúng khá khác nhau.
tripleee

Câu trả lời:


91

Mẫu \dcó thể không được hỗ trợ bởi của bạn sed. Hãy thử [0-9]hoặc [[:digit:]]thay thế.

Để chỉ in kết quả phù hợp thực tế (không phải toàn bộ dòng so khớp), hãy sử dụng thay thế.

sed -n 's/.*\([0-9][0-9]*G[0-9][0-9]*\).*/\1/p'

6
Cảm ơn nó hoạt động tốt. Nhưng tôi có một câu hỏi tại sao lại .*cần thiết với regex của bạn vì khi tôi thử sed -n 's/\([0-9]\+G[0-9]\+\)/\1/p'nó chỉ in toàn bộ dòng.
RanRag

7
Đó là lý do tại sao, phải không? Thay thế bất kỳ thứ gì đứng trước và sau trận đấu bằng ký hiệu, sau đó in toàn bộ dòng.
tripleee

1
@tripleee Cái này chỉ in 2G05không 02G05. Biểu thức hoạt động là's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
Kshitiz Sharma 12/1213

1
Mã cứng đó thành chính xác hai chữ số. Một cái gì đó giống như sed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'sẽ được tổng quát hơn. (Tôi giả sử bạn sedhỗ trợ \?cho không hoặc một xảy ra.)
tripleee

Xem thêm stackoverflow.com/a/48898886/874188 cho làm thế nào để thay thế khác nhau phổ biến khác Perl thoát như \w, \svv
tripleee

99

Làm thế nào về việc sử dụng grep -E?

echo "This is 02G05 a test string 20-Jul-2012" | grep -Eo '[0-9]+G[0-9]+'

3
+1 Điều này đơn giản hơn và cũng sẽ xử lý chính xác trường hợp nhiều kết quả trùng khớp trên cùng một dòng. Một sedkịch bản phức tạp có thể được nghĩ ra cho trường hợp đó, nhưng tại sao phải bận tâm?
tripleee

egrepsử dụng regexp mở rộng sedgrepsử dụng regexp tiêu chuẩn egrephoặc grep -ehoặc sed -Esử dụng regexp mở rộng và mã python trong câu hỏi sử dụng PCRE, (biểu thức chính quy perl) GNU grep có thể sử dụng PCRE với -Ptùy chọn.
Felipe Buccioni

@FelipeBuccioni thực sự cần được egrephoặc grep -Ehoặcsed -r
SensorSmith

Đối với một trận đấu (đầu tiên), hãy nối thêm `| đầu -1` (không có dấu gạch ngược), theo câu trả lời này cho câu hỏi khác.
SensorSmith

1
grep-m 1phải dừng lại sau trận đấu đầu tiên.
tripleee

5

sedkhông nhận ra \d, hãy sử dụng [[:digit:]]thay thế. Bạn cũng sẽ cần thoát +hoặc sử dụng công -rtắc ( -Etrên OS X).

Lưu ý rằng điều đó cũng [0-9]hoạt động với các chữ số Ả Rập-Hindu.


Tôi đã thử sed -n '/[0-9]\+G[0-9]\+/p'. Bây giờ nó chỉ in toàn bộ chuỗi
RanRag

@Noob: Bạn sẽ cần sử dụng tính năng thay thế để loại trừ những phần bạn không muốn in .
Tạm dừng cho đến khi có thông báo mới.

5

Hãy thử cái này thay thế:

echo "This is 02G05 a test string 20-Jul-2012" | sed 's/.* \([0-9]\+G[0-9]\+\) .*/\1/'

Nhưng lưu ý, nếu có hai mẫu trên một dòng, nó sẽ in thứ hai.


Hay nói chung là cái cuối cùng nếu có nhiều trận đấu.
tripleee

0

Hãy thử sử dụng rextract . Nó sẽ cho phép bạn trích xuất văn bản bằng biểu thức chính quy và định dạng lại nó.

Thí dụ:

$ echo "This is 02G05 a test string 20-Jul-2012" | ./rextract '([\d]+G[\d]+)' '${1}'

2G05

Nếu điều này sử dụng regex tiêu chuẩn, thì các dấu ngoặc vuông xung quanh \dlà hoàn toàn thừa.
tripleee
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.