Nhóm kết hợp lồng nhau trong regex


8

Tôi có một usecase chung khi tôi chuyển đổi một số biểu thức python theo cách sau:

value 1
value 2
value 3

vào

['value 1', 'value 2', 'value 3']

Cách dễ nhất có thể là sử dụng ánh xạ, nhưng tôi muốn sử dụng thay thế cho tác vụ này.

Cho đến nay tôi đã nhận được:

s/\(.*\n\)\+/[&]/g

Kết quả nào

[value 1
value 2
value 3
]

Điều này đặt ra một câu hỏi, bởi vì tôi muốn có thể khớp \(.*\), nhưng không phải \nvà việc sử dụng kết quả của kết quả khớp bên trong a '...'.

Bạn có biết làm thế nào để làm điều này?


2
Tôi không biết cách thực hiện trong một thay thế duy nhất, nhưng bạn có thể làm điều đó trong 2 trong khi ở chế độ trực quan (sau khi chọn biểu thức python): :'<,'>s/\v(.*)\n/'\1', / | s/\v(.*), /[\1]/Bạn có thể chuyển đổi nó thành ánh xạ trực quan: xnoremap ,x :s/\v(.*)\n/'\1', / <Bar> s/\v(.*), /[\1]/<CR>và có thể thành ánh xạ bình thường nếu biểu thức là bên trong một đoạn: nnoremap ,x :'{+1,'}-1s/\v(.*)\n/'\1', / <Bar> s/\v(.*), /[\1]/<CR>Ở đây ánh xạ sẽ là ,x.
dùng9433424

1
không thể làm với regex, nhưng sử dụng các lệnh bên ngoài:%! echo "[$(sed "s/.*/'&',/" % | tr '\n' ' ' | sed 's/, $//')]"
Sundeep

Câu trả lời:


5

Biên tập

Có thể thực hiện việc này trong một biểu thức nếu chúng ta sử dụng "biểu thức thay thế phụ". Xem dưới cùng để biết thông tin về điều đó.

/Biên tập

Vấn đề ở đây là bạn muốn làm hai việc khác nhau.

  1. Hoạt động trên toàn bộ trận đấu (nghĩa là bao quanh nó [])

  2. Hoạt động trên từng mục trong trận đấu (nghĩa là bao quanh chúng '',)

Bạn có thể dễ dàng thực hiện một trong hai:

  1. :s/\(.\+\n\)\+/[&]/
  2. :%s/\(.\+\)\n/'\1', /

nhưng theo tôi biết không có cách nào để thực hiện cả hai trong một thao tác. Tôi đã cố gắng để có được đầu ra thích hợp với một cái gì đó như:

:s/\(\(.\+\)\n\)\+/[\2]/

Nhưng tất nhiên, vấn đề với điều này là các \2trận đấu chỉ có trận đấu cuối cùng từ tập hợp dấu ngoặc đơn thứ hai \(\)và không "nhớ" bất cứ điều gì trước đó. Vì vậy, bạn kết thúc với chỉ dòng cuối cùng.

Tôi sẽ khuyên bạn nên thực hiện một số xử lý trước / sau với một :s///lệnh bổ sung để loại bỏ các dòng mới trước / sau thực tế. Đây là những gì tôi nghĩ ra

function! FormatExpression()
   .,/\n^$/s/\(.*\)\n/'\1', /
   s/\(.*\), /[\1]/
endfunction

Dòng thứ 1 (Xóa dòng mới)

  • .,/\n^$/Đây là một sửa đổi phạm vi cho tìm kiếm và thay thế. Nếu không có điều này, lệnh sẽ tiếp tục cắt xén toàn bộ tệp của bạn. Hiện tại nó đi từ dòng hiện tại ., đến dòng trống tiếp theo \n^$. Tôi không chắc làm thế nào bạn có ý định chia nhỏ mọi thứ, nhưng bạn cần một số cách để bảo nó dừng lại.
  • s/ Bắt đầu một lệnh tìm kiếm và thay thế
  • \(.*\)\n Khớp toàn bộ dòng, nhưng chỉ lưu phần mà không có dòng mới.
  • '\1', Thay thế dòng bằng trận đấu được bao quanh bởi dấu ngoặc đơn và thêm dấu phẩy.

Dòng thứ 2 (Bao quanh trong ngoặc)

  • \(.*\), Khớp toàn bộ dòng nhưng không phải dấu phẩy và dấu cách cuối cùng
  • [\1] Xung quanh với dấu ngoặc và cũng loại bỏ dấu phẩy và dấu cách kết thúc không cần thiết.

Tôi sẽ tiếp tục xem xét điều này, nhưng hiện tại tôi không nghĩ rằng nó có thể với một biểu thức duy nhất. :

BIÊN TẬP:

Tôi đã tìm thấy một cách để làm điều này với một biểu thức! Trong nội bộ, đây thực sự là hai sự thay thế, nhưng về mặt kỹ thuật một biểu thức. Đây là những gì tôi nghĩ ra:

:s/\v((.+\n)*.+)\n/\= "['" . substitute(submatch(1), '\n', "', '", 'g') . "']" /
  • :s///: Thay người
  • \v((.+\n)*.+)\n: Về cơ bản tập hợp tất cả các dòng không trống tiếp theo và lưu trữ tất cả ngoại trừ cuối cùng \n
  • \=Cho phép chúng tôi sử dụng một biểu thức trong thay thế (xem :h sub-replace-expression)
  • substitute(submatch(1)...): Thay thế tất cả được lưu trữ \nvới', '
  • "['" . ... . "']": Chuẩn bị ['và bổ sung']

Điều này sẽ bắt đầu tại vị trí của con trỏ và đi cho đến khi tìm thấy một dòng trống ( ^\n). Không nắm lấy cái cuối cùng \nlà điều quan trọng vì không có bit đó, chúng ta còn lại một phần bổ sung ',mà chúng ta không muốn ở cuối.

Một số có thể xem xét điều này phức tạp hơn câu trả lời hai biểu thức trước đó. Nhưng tôi nghĩ rằng tôi sẽ tiếp tục và thêm điều này vì trên thực tế có thể làm điều đó với một biểu thức. :)


2

Nổi bật trực quan, sau đó:

:'<,'> s/.*/['&']/ | *j! | s/]\[/, /ge

Nó bao quanh mỗi dòng, ví dụ ['value 1'], tham gia tất cả chúng, sau đó thay thế liền kề ][bằng dấu phẩy.

Các tài liệu cho *trong *j!:help cpo-star, bằng cách này. Đó là một chút khó khăn để tìm thấy.


Làm việc tốt xung quanh :)
nobe4 29/07/2016

Trên thực tế bạn có thể sử dụng :'<,'>s/\v(.*)(\_.)/['\1']/và loại bỏ việc tham gia.
nobe4

Vâng, nhưng nó ăn cuối cùng \n, đó là lý do tại sao tôi sử dụng :join. Tôi có lẽ nên đề cập đến điều đó. :-)
Antony

1
Làm thế nào về '<,'>s/.*/['&']/ | *s/]\_.\[/, /sau đó?
nobe4

1
Vâng, điều đó tốt hơn. Mặc dù tôi có thể viết phần thứ hai là *s/]\n\[/, /e.
Antony
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.