Tại sao tôi cần phải thoát các ký tự regex trong sed để được hiểu là các ký tự regex?


11

Có vẻ như
cat sed_data.txt | sed 's/\b[0-9]\{3\}\b/NUMBER/g'
tôi phải thoát các ký tự để tạo thành một biểu thức chính quy. Trong trường hợp này, tôi đã phải thoát khỏi niềng răng để được hiểu là một số lần.
Tại sao? Tôi đã mong đợi rằng mọi thứ sẽ là một nhân vật regex trừ khi trốn thoát. Tức là ngược lại.


Có một bài viết về tìm kiếm trong Vim phần nào bao gồm câu hỏi này, phiên bản ngắn là "nó phụ thuộc vào việc thực hiện lệnh" ... unix.stackexchange.com/questions/90345/
Drav Sloan

@DravSloan: Tôi không chắc nó giống nhau. Trong Vim bạn tìm kiếm văn bản theo mặc định và bạn cần thoát để tìm kiếm regex. Nhưng trong trường hợp này định dạng s/regex//gđã mong đợi một regex và tôi sẽ mong rằng đó là văn bản cần để được trốn thoát
Jim

Câu trả lời:


14

Điều này là do sedsử dụng POSIX BREs (Biểu thức chính quy cơ bản) trái ngược với ERE (Biểu thức chính quy mở rộng) mà bạn có thể đã sử dụng từ Perl hoặc bạn bè.

Từ sed(1)trang người đàn ông:

REGULAR EXPRESSIONS
       POSIX.2 BREs should be supported, but they aren't completely because of
       performance problems.  The \n sequence in a regular expression  matches
       the newline character, and similarly for \a, \t, and other sequences.

Trích dẫn có liên quan từ các liên kết trên:

Hương vị thông thường cơ bản hoặc hương vị BRE tiêu chuẩn hóa một hương vị tương tự như hương vị được sử dụng bởi lệnh grep UNIX truyền thống. Đây là khá nhiều hương vị biểu hiện thường xuyên lâu đời nhất vẫn còn được sử dụng ngày nay. Một điều làm nổi bật hương vị này là hầu hết các nhân vật metachar yêu cầu một dấu gạch chéo ngược để cung cấp cho metacharacter hương vị của nó. Hầu hết các hương vị khác, bao gồm POSIX ERE, sử dụng dấu gạch chéo ngược để loại bỏ ý nghĩa của siêu ký tự.

Trích dẫn nguyên văn từ bình luận của Craig Sanders :

Lưu ý rằng trong GNU sed ít nhất, bạn có thể yêu cầu sed sử dụng biểu thức chính mở rộng với tùy chọn dòng lệnh -r hoặc --regrec-Extended. Điều này rất hữu ích nếu bạn muốn tránh làm xấu đi kịch bản sed của bạn với việc thoát quá mức.


1
Lưu ý rằng trong GNU sed ít nhất, bạn có thể yêu cầu sed sử dụng biểu thức chính mở rộng với tùy chọn -rhoặc --regexp-extendeddòng lệnh. Điều này rất hữu ích nếu bạn muốn tránh làm xấu đi kịch bản sed của bạn với việc thoát quá mức.
cas

@CraigSanders Cảm ơn vì điều này. Thêm vào để trả lời.
Joseph R.

@CraigSanders, các sedtriển khai khác (khi chúng hỗ trợ ERE, chủ yếu là BSD) có xu hướng sử dụng -Echo điều đó thay vào đó (điều này có ý nghĩa hơn nhiều vì đó là lựa chọn tương tự như vậy grep. Tại sao GNU sedchọn -rlà một bí ẩn đối với tôi).
Stéphane Chazelas

Vâng, một bí ẩn đối với tôi quá. Nó sẽ có ý nghĩa hơn để sử dụng -E. và sau đó thêm -F, -G và -P để khớp với GNU grep. IMO gawk sẽ được hưởng lợi từ cùng một RE lập luận quá ... hoặc ít nhất, -P.
cas

12

Đó là vì lý do lịch sử.

Regapi lần đầu tiên được giới thiệu trong Unix trong edtiện ích vào đầu những năm 70. Mặc dù edđược dựa trên qedmà thực hiện bởi các tác giả cùng hiểu regexp phức tạp hơn, edchỉ hiểu ^, $, [...], ., *\để thoát khỏi tất cả những điều trên.

Bây giờ, khi cần phải có nhiều toán tử phát sinh, một cách đã được tìm thấy để giới thiệu chúng mà không phá vỡ tính tương thích ngược. Nếu một kịch bản sử dụng để sử dụng các s edlệnh như s/foo() {/foo (var) {/gđể thay thế tất cả các trường hợp foo() {foo(var) { và bạn đã giới thiệu một (hoặc {điều hành, điều đó sẽ phá vỡ kịch bản đó.

Tuy nhiên, không có kịch bản nào có thể làm được s/foo\(\) {/foo\(var\) {/, vì điều đó giống như s/foo() {/foo(var) {/và không có lý do gì để thoát (vì đó không phải là toán tử RE. Vì vậy, việc giới thiệu một toán tử mới \(hoặc \{toán tử không phá vỡ tính tương thích ngược vì rất khó có thể phá vỡ một tập lệnh hiện có bằng cú pháp cũ hơn.

Vì vậy, đó là những gì đã được thực hiện. Sau đó, \(...\)được thêm vào ban đầu chỉ để s edlệnh thực hiện những việc như s/foo\(.\)/\1bar/và sau đó là grep '\(.\)\1'(nhưng không phải là những thứ như \(xx\)*).

Trong UnixV7 (1979, gần một thập kỷ sau), một dạng biểu thức chính quy mới đã được thêm vào trong phần mới egrepawkcác tiện ích gọi là biểu thức chính quy mở rộng (vì chúng là các công cụ mới, không có khả năng tương thích ngược bị phá vỡ). Cuối cùng, nó cung cấp chức năng có sẵn trong cổ đại của Ken Thompson qed(toán tử thay thế |, nhóm (..)*) và thêm một vài toán tử thích +?(nhưng không có tính năng backref của các biểu thức chính quy cơ bản).

Sau đó, các BSD đã thêm \<\>(vào cả BRE và ERE), và SysV chỉ thêm \{\}vào BREs.

Mãi cho đến khi muộn hơn {}được thêm vào ERE, bằng cách phá vỡ tính tương thích ngược. Không phải ai cũng thêm nó. Chẳng hạn, GNU awkcho đến phiên bản 4.0.0 (2011) không hỗ trợ {trừ khi bị ép buộc vào chế độ tuân thủ POSIX.

Khi GNU grepđược viết vào đầu những năm 90, nó đã thêm tất cả các ưu điểm từ cả BSD và SysV (như \<, {) và thay vì có hai cú pháp regrec và công cụ riêng cho BRE và ERE, đã triển khai cùng một toán tử trong cả hai, chỉ các đối tác BRE của (, ?, {, +phải được bắt đầu bằng một dấu gạch chéo (để tương thích với việc triển khai BRE khác). Đó là lý do tại sao bạn có thể làm .\+trong GNU grep(mặc dù đó không phải là POSIX hoặc được hỗ trợ bởi các triển khai khác) và bạn có thể làm (.)\1trong GNU egrep(mặc dù đó không phải là POSIX hoặc được hỗ trợ bởi nhiều triển khai khác bao gồm cả GNU awk).

Thêm \xtoán tử không phải là cách duy nhất để thêm nhiều toán tử theo cách tương thích ngược. Ví dụ, perlđược sử dụng (?...). Điều đó vẫn tương thích ngược với ERE vì (?=...)không hợp lệ trong ERE, tương tự như vậy .*?. vimđối với các nhà khai thác tương tự đã làm điều đó khác nhau bằng cách giới thiệu \@=hoặc .\{-}ví dụ.

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.