Làm cách nào để sử dụng [\ w] + trong biểu thức chính quy trong sed?


24

Tôi đang ở trên Windows, nhưng tôi đoán câu hỏi của tôi vẫn được đặt đúng ở đây.

C:\Users\User>grep --version
GNU grep 2.6.3

C:\Users\User>sed --version
GNU sed version 4.2.1

Tôi nhận thấy rằng các công việc sau đây (đầu ra here):

echo here | grep -E "\w+"
echo here | grep -E "[her]+"

Nhưng, điều này không hoạt động (không xuất hiện gì):

echo here | grep -E "[\w]+"

Điều này một lần nữa không (xuất here)

echo here | grep -P "[\w]+"

Vì vậy, [\w]một cái gì đó cụ thể cho biểu thức chính quy Perl, tôi giả sử. Đúng không?

Vì vậy, hãy nói chuyện sed. Công việc này (xuất ra gone):

echo here | sed -r "s/\w+/gone/"
echo here | sed -r "s/[her]+/gone/"

Và một lần nữa, điều này không (xuất ra here):

echo here | sed -r "s/[\w]+/gone/"

Bây giờ, làm thế nào tôi có thể kích hoạt biểu thức chính quy Perl cho sed - có cách nào không?

Câu trả lời:


11

Các công cụ và phiên bản khác nhau của chúng hỗ trợ các biến thể khác nhau của biểu thức chính quy. Các tài liệu của mỗi sẽ cho bạn biết những gì họ hỗ trợ.

Các tiêu chuẩn tồn tại để người ta có thể dựa vào một bộ tính năng tối thiểu có sẵn trên tất cả các ứng dụng phù hợp.

Ví dụ, tất cả các triển khai hiện đại sedgrepthực hiện các biểu thức chính quy cơ bản theo quy định của POSIX (ít nhất là một phiên bản hoặc phiên bản khác của tiêu chuẩn, nhưng tiêu chuẩn đó đã không phát triển nhiều về vấn đề đó trong vài thập kỷ qua).

Trong POSIX BRE và ERE, bạn có [:alnum:]lớp nhân vật. Điều đó khớp với các chữ cái và chữ số trong miền địa phương của bạn (lưu ý thường bao gồm nhiều hơn a-zA-Z0-9trừ khi miền địa phương là C).

Vì thế:

grep -x '[[:alnum:]_]\{1,\}'

phù hợp với một hoặc nhiều alnums hoặc _.

[\w]được POSIX yêu cầu để khớp với dấu gạch chéo ngược hoặc w. Vì vậy, bạn sẽ không tìm thấy grephoặc sedthực hiện ở nơi có sẵn (trừ khi thông qua các tùy chọn không chuẩn).

Hành vi cho \wmột mình không được chỉ định bởi POSIX, vì vậy việc triển khai được phép thực hiện những gì họ muốn. GNU grepnói thêm rằng một thời gian dài trước đây.

GNU grepđã từng có công cụ regrec riêng của mình, tuy nhiên hiện tại nó sử dụng công cụ GNU libc (mặc dù nó có nhúng bản sao của chính nó).

Nó có nghĩa là để phù hợp với alnums và gạch dưới trong miền địa phương của bạn. Tuy nhiên, hiện tại nó có một lỗi ở chỗ nó chỉ khớp với các ký tự một byte (ví dụ, không phải là ngôn ngữ UTF-8 mặc dù đó rõ ràng là một chữ cái và mặc dù nó khớp với tất cả các địa phương trong đó é là một ký tự tính cách).

Ngoài ra còn có một \wtoán tử regrec trong perl regrec và trong PCRE. PCRE / perl không phải là biểu thức chính quy POSIX, chúng chỉ là một thứ khác hoàn toàn.

Bây giờ, với cách GNU grep -Psử dụng PCRE, nó có vấn đề tương tự như không có -P. Nó có thể được xử lý xung quanh đó bằng cách sử dụng (*UCP)(mặc dù điều đó cũng có tác dụng phụ ở các địa phương không phải UTF8).

GNU sedcũng sử dụng regexs của GNU libc cho các biểu thức chính của nó. Nó sử dụng nó theo cách như vậy mặc dù nó không có lỗi tương tự như GNU grep.

GNU sedkhông hỗ trợ PCRE. Có một số bằng chứng trong mã rằng nó đã được thử trước đó, nhưng dường như nó không còn nằm trong chương trình nghị sự nữa.

Nếu bạn muốn biểu thức chính quy của Perl, chỉ cần sử dụng perl.

Mặt khác, tôi nói rằng thay vì cố gắng dựa vào một tính năng không chuẩn không có thật của việc triển khai sed/ cụ thể của bạn grep, thì tốt hơn là nên tuân thủ tiêu chuẩn và sử dụng [_[:alnum:]].


[_[:alnum:]]là một cách giải quyết tốt cho phép tôi mở rộng nó giống như [\w/]( [_[:alnum:]/]trong trường hợp đó).
bers

1
Câu trả lời này hiện đã lỗi thời liên quan đến các hạn chế của GNU grep.
Stéphane Chazelas

7

Bạn đã đúng - \wlà một phần của PCRE - biểu thức chính quy tương thích perl. Nó không phải là một phần của regex 'tiêu chuẩn'. http://www.THER-expressions.info/poseix.html

Một số phiên bản sedcó thể hỗ trợ nó, nhưng tôi đề nghị cách dễ nhất là chỉ sử dụng perltrong sedchế độ bằng cách chỉ định -pcờ. (Cùng với -e). (Chi tiết hơn trong perlrun)

Nhưng bạn không cần []xung quanh nó trong ví dụ đó - đó là cho các nhóm công cụ hợp lệ.

echo here  | perl -pe 's/\w+/gone/'

Hoặc trên Windows:

C:\>echo here  | perl -pe "s/\w+/gone/"
gone
C:\>echo here  | perl -pe "s/[\w\/]+/gone/"
gone

Xem perlređể biết thêm công cụ PCRE.

Bạn có thể nhận được perl tại đây: http://www.activestate.com/activeperl/doads


Xin lưu ý sự khác biệt giữa \w[\w]trong câu hỏi của tôi. Tôi sẽ cập nhật nó với đầu ra của mỗi lệnh để làm rõ cái nào đang hoạt động và cái nào không. Đặc biệt, sedhiểu \w, nhưng không [\w]. Ngoài ra, tôi cần [\w]phải làm việc vì tôi muốn sử dụng [\w/]chẳng hạn.
bers

Trong trường hợp đó, nó có thể là một vấn đề trích dẫn. Dù bằng cách nào - perlcó thể làm được :).
Sobrique

Cảm ơn! Câu trả lời của Stéphane Chazelas gần hơn một chút so với những gì tôi yêu cầu (vì tôi chưa cài đặt perl - một người dùng Windows du * b, tôi đoán vậy), vì vậy tôi đã chấp nhận câu trả lời của anh ấy.
bers

Điều đó ổn - nhưng tôi khuyên bạn nên cài đặt Perl trên Windows. Đó là một trong những điều đầu tiên thuộc về tôi và tôi thấy nó vô cùng hữu ích.
Sobrique

\wlà trong GNU grep (vào những năm 80) trước khi ở perl và trong GNU emacs có lẽ thậm chí trước đó.
Stéphane Chazelas

1

Tôi nghi ngờ điều đó grepsedđang quyết định khác nhau khi nào nên áp dụng []và khi nào nên mở rộng \w. Trong perl regex \wcó nghĩa là bất kỳ ký tự từ nào và []xác định một nhóm để áp dụng bất kỳ ký tự nào trong một kết hợp. Nếu bạn "mở rộng" \wtrước thì []nó sẽ là một lớp ký tự của tất cả các ký tự từ. Nếu, thay vào đó, []trước tiên bạn sẽ có một lớp nhân vật có hai ký tự \wdo đó, nó sẽ khớp với bất kỳ mẫu nào chứa một hoặc nhiều trong hai ký tự đó.

Vì vậy, có vẻ như sedđang nhìn thấy []và coi nó như chứa các ký tự chính xác để khớp thay vì tôn vinh trình tự đặc biệt \wnhư perlgreplàm. Tất nhiên, điều []này là hoàn toàn không cần thiết trong ví dụ này, nhưng người ta có thể tưởng tượng ra những trường hợp quan trọng, nhưng sau đó bạn có thể làm cho nó hoạt động với parens và ors.


Tôi sẽ ngạc nhiên nếu đó là như vậy. \ là một mã thoát và bạn sẽ sử dụng nó để thoát các dấu phân cách. Điều đó có nghĩa là nó phải có quyền ưu tiên cao hơn bất kỳ điều gì khác. Tôi nghĩ nhiều khả năng nó không được triển khai vì \wkhông phải là một phần của thông số biểu thức chính quy
Sobrique

Chà, theo kinh nghiệm thì có vẻ như đó là trường hợp sử dụng gnu sed cho tôi: echo whe\\ere | sed -r 's/[\w]+/gone/gcho tôi gonehegoneerenhư thể nó phù hợp với từng ` and w` và thực hiện thay thế
Eric Renouf

Tôi có thể xác nhận những gì Eric Renouf đang nhìn thấy. Vì vậy, chúng tôi muốn unescape dấu gạch chéo ngược bằng cách nào đó? :)
bers

Tôi không nghĩ đó là câu trả lời đúng. Sed chỉ không hỗ trợ trộn các loại định nghĩa lớp nhân vật khác nhau, vì vậy câu trả lời là nếu bạn phải sử dụng cả hai loại lớp nhân vật, hãy chọn một công cụ khác hoặc nếu bạn chọn sed sử dụng cú pháp mà nó hỗ trợ
Eric Renouf
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.