Bạn cần thay thế bằng một nhà nước. Tôi nhớ đã cung cấp một (/ vài?) Giải pháp hoàn chỉnh cho loại vấn đề này trên SO.
Đây là một cách khác để tiến hành (1). Bây giờ, tôi sẽ tiến hành thành 2 bước:
- một biến danh sách giả tôi cần cho thủ thuật bẩn thỉu và hỗn độn mà tôi sẽ sử dụng
- một sự thay thế trong đó tôi chèn len của mảng giả này tôi sẽ điền vào mỗi lần xuất hiện khớp.
Cung cấp cho:
:let t=[]
:%s/#\zs\d\+\(\.\d\+\)\=\ze/\=len(add(t,1))/g
Nếu bạn chưa quen với vim regexes, tôi sử dụng :h /\zs
và \ze
chỉ định mẫu phụ nào tôi phù hợp, thì tôi khớp một loạt các chữ số có thể theo sau là dấu chấm và các chữ số khác. Điều này không hoàn hảo cho bất kỳ số dấu phẩy động nào, nhưng điều này là đủ ở đây.
Lưu ý: Bạn sẽ phải gói nó trong một vài chức năng + lệnh cho một giao diện đơn giản. Một lần nữa, có những ví dụ về SO / vim ( ở đây , ở đây , ở đây ) Ngày nay tôi biết đủ vim để không quan tâm đến việc gói thủ thuật này vào một lệnh. Thật vậy, tôi sẽ có thể viết lệnh này trong lần thử đầu tiên, trong khi tôi sẽ mất vài phút để nhớ tên của lệnh.
(1) Mục tiêu là có thể duy trì trạng thái ở giữa các sự thay thế và thay thế sự xuất hiện hiện tại bằng một điều gì đó phụ thuộc vào trạng thái hiện tại.
Nhờ :s\=
chúng tôi có thể chèn một cái gì đó từ một tính toán.
Vẫn là vấn đề của nhà nước. Hoặc chúng tôi xác định một chức năng quản lý trạng thái bên ngoài hoặc chúng tôi tự cập nhật trạng thái bên ngoài. Trong C (và các ngôn ngữ liên quan), chúng ta có thể đã sử dụng một cái gì đó như length++
hoặc length+=1
. Thật không may, trong các tập lệnh vim, +=
không thể được sử dụng ra khỏi hộp. Nó cần phải được sử dụng với :set
hoặc với :let
. Điều này có nghĩa là :let length+=1
tăng một số, nhưng không trả về bất cứ thứ gì. Chúng tôi không thể viết :s/pattern/\=(length+=1)
. Chúng tôi cần một cái gì đó khác.
Chúng ta cần các chức năng đột biến. tức là các chức năng làm thay đổi đầu vào của chúng. Chúng tôi có setreg()
, map()
, add()
và có lẽ nhiều hơn nữa. Hãy bắt đầu với họ.
setreg()
đột biến một đăng ký. Hoàn hảo. Chúng ta có thể viết setreg('a',@a+1)
như trong giải pháp của @Doktor OSwaldo. Tuy nhiên, điều này là không đủ. setreg()
là một thủ tục hơn là một hàm (đối với những người trong chúng ta biết Pascal, Ada ...). Điều này có nghĩa là nó không trả lại bất cứ điều gì. Trên thực tế, nó trả lại một cái gì đó. Lối ra danh nghĩa (tức là lối thoát không ngoại lệ ) luôn trả lại một cái gì đó. Theo mặc định, khi chúng tôi quên trả lại một cái gì đó, 0 được trả về - nó cũng được áp dụng với các hàm tích hợp. Đó là lý do tại sao trong giải pháp của mình, biểu thức thay thế là thực sự \=@a+setreg(...)
. Tricky, phải không?
map()
cũng có thể được sử dụng. Nếu chúng tôi bắt đầu từ một danh sách với một 0 ( :let single_length=[0]
), chúng tôi có thể tăng nó nhờ map(single_length, 'v:val + 1')
. Sau đó, chúng ta cần phải trả lại chiều dài mới. Không giống như setreg()
, map()
trả về đầu vào đột biến của nó. Thật hoàn hảo, độ dài được lưu trữ ở vị trí đầu tiên (và duy nhất, và do đó cũng kéo dài) của danh sách. Các biểu thức thay thế có thể là \=map(...)[0]
.
add()
là thói quen tôi thường sử dụng theo thói quen (thực ra tôi chỉ nghĩ về điều đó map()
và tôi chưa chuẩn bị màn trình diễn tương ứng của họ). Ý tưởng với add()
là sử dụng một danh sách làm trạng thái hiện tại và nối thêm một cái gì đó vào cuối trước mỗi lần thay thế. Tôi thường lưu trữ giá trị mới ở cuối danh sách và sử dụng nó để thay thế. Cũng như add()
trả về danh sách đầu vào đột biến của nó, chúng ta có thể sử dụng : \=add(state, Func(state[-1], submatch(0)))[-1]
. Trong trường hợp của OP, chúng ta chỉ cần nhớ có bao nhiêu trận đấu đã được phát hiện cho đến nay. Trả lại độ dài của danh sách nhà nước này là đủ. Do đó của tôi \=len(add(state, whatever))
.
perldo
, bạn có thể sử dụng:%perldo s/#\K\d+(\.\d+)?/++$i/ge