2016-03-11 20 views
5

Ví dụ: tôi có văn bản có nhiều kích thước sản phẩm như "2x4" mà tôi muốn chuyển đổi thành "2 xby 4".Cách thay thế tất cả các lần xuất hiện của regex như thể áp dụng thay thế liên tục

pattern = r"([0-9])\s*[xX\*]\s*([0-9])" 

re.sub(pattern, r"\1 xby \2", "2x4") 
'2 xby 4' # good 

re.sub(pattern, r"\1 xby \2", "2x4x12") 
'2 xby 4x12' # not good. need this to be '2 xby 4 xby 12' 

Một cách để mô tả những gì tôi muốn làm là lặp lại thay thế cho đến khi không thể thay thế thêm. Ví dụ, tôi có thể chỉ đơn giản là để thay thế trên hai lần để có được những gì tôi muốn

x = re.sub(pattern, r"\1 xby \2", "2x4x12") 
x = re.sub(pattern, r"\1 xby \2", x) 
'2 xby 4 xby 12' 

Nhưng tôi giả sử có một cách tốt hơn

Trả lời

5

Bạn có thể sử dụng lookahead regex này cho tìm kiếm:

r'([0-9]+)\s*[xX*]\s*(?=[0-9]+)' 

(?=[0-9]+) là lookahead tích cực mà chỉ khẳng định sự hiện diện của số thứ hai bằng cách nhìn về phía trước nhưng không di chuyển con trỏ regex nội bộ bằng cách kết hợp các số.

Và sử dụng này để thay thế:

r'\1 xby ' 

RegEx Demo

Code:

>>> pattern = r'([0-9]+)\s*[xX*]\s*(?=[0-9]+)' 

>>> re.sub(pattern, r'\1 xby ', "2x4") 
'2 xby 4' 

>>> re.sub(pattern, r'\1 xby ', "2x4x12") 
'2 xby 4 xby 12' 
+1

Tôi nghĩ rằng tôi thích điều này tốt hơn mặc dù tôi nghĩ rằng tôi đã có câu trả lời. Lookahead sẽ nhận được nó kể từ khi thay thế được thực hiện trái sang phải. – NickT

+1

Cảm ơn. Bạn có thể giải thích một cách lỏng lẻo về việc này đang làm gì không? Có vẻ như đúng, nhưng tôi không hoàn toàn hiểu tại sao. – Ben

+1

Tôi đã thêm một lời giải thích về lookahead trong câu trả lời. – anubhava

0

Vì bạn đang cố gắng để chạy lại trận đấu chống lại văn bản có đã được biến đổi bởi regex, không thực sự là một cách tốt hơn.

Nó giống như giải quyết một vấn đề toán học, nếu bạn muốn làm: (2 + 3) + 4, bạn cần phải thay thế "(2 + 3)" để có thể thay thế "5 + 4" vì chuỗi "5" không ở đâu trong văn bản gốc của bạn.

Những gì bạn có thể muốn làm là kiểm tra chuỗi của bạn cho bất kỳ kết quả phù hợp nào và tiếp tục chạy lại các kết quả trước đó cho đến khi không tìm thấy kết quả nào khác.

Chỉnh sửa: Bạn cũng có thể chỉ thực hiện một vài regex cho số lần nó có thể lặp lại và chạy chúng theo thứ tự độ dài giảm dần. I E. tìm kiếm 2x3x5x2 rồi 2x3x5 rồi 2x3, vì dần dần bạn sẽ không đánh bất cứ thứ gì đã được thay thế.

1

Tôi nghĩ rằng bạn có thể tiếp cận với một pass duy nhất, bởi suy nghĩ một chút khác nhau về nó. Những gì bạn đang thực sự cố gắng làm là thay thế x bằng xby - vì vậy bạn có thể quét toàn bộ chuỗi một lần, nếu bạn không tiêu thụ phía bên phải của các chữ số.

Đối với điều này, tôi khuyên bạn nên xác nhận xem trước. Về cơ bản, xác nhận rằng điều bạn đang thay thế được theo sau bởi các chữ số, nhưng không ăn các chữ số trong tiến trình. Ký hiệu này là (? = ...) - xem re docpage.

Đối với tôi, tôi có sau - lưu ý rằng biên soạn regex là không bắt buộc và \ d thường được ưa chuộng hơn [0-9]:

pattern = re.compile(r"(\d+)\s*[xX\*]\s*(?=\d)") 
pattern.sub(r"\1 xby ", "2x4x12") 

'2 xby 4 xby 12' 

Trong một vượt qua, nó sẽ xử lý toàn bộ chuỗi .

Các vấn đề liên quan