regex để khớp, nhưng chỉ thay thế một phần của mẫu, trong python

Aug 17 2020

Tất cả các ví dụ tôi đã tìm thấy về tràn ngăn xếp quá phức tạp để tôi thiết kế ngược lại .

Hãy xem xét ví dụ đồ chơi này

s = "asdfasd a_b dsfd"

tôi muốn s = "asdfasd a'b dsfd"

Đó là: tìm hai ký tự được phân tách bằng dấu gạch dưới và thay dấu gạch dưới đó bằng dấu nháy đơn

Cố gắng:

re.sub("[a-z](_)[a-z]","'",s)
# "asdfasd ' dsfd"

Tôi nghĩ rằng ()phải giải quyết vấn đề này?

Điều khó hiểu hơn nữa là có vẻ như chúng tôi đã tìm thấy thành công nhân vật mà chúng tôi muốn thay thế:

re.findall("[a-z](_)[a-z]",s)
#['_']

tại sao cái này không được thay thế?

Cảm ơn

Trả lời

3 Marat Aug 17 2020 at 00:27

Sử dụng các mẫu nhìn trước và nhìn sau:

re.sub("(?<=[a-z])_(?=[a-z])","'",s)

Các mẫu nhìn trước / sau không có độ rộng bằng 0 và do đó không thay thế bất cứ thứ gì.

CẬP NHẬT:

  • Vấn đề là nó re.subsẽ thay thế toàn bộ biểu thức phù hợp, bao gồm cả chữ cái đứng trước và chữ cái sau.
  • re.findallvẫn khớp với toàn bộ biểu thức, nhưng nó cũng có một nhóm (dấu ngoặc đơn bên trong), bạn đã quan sát thấy. Cả trận đấu vẫna_b
  • biểu thức lookahead / lookbehind kiểm tra xem tìm kiếm có đứng trước / theo sau bởi một mẫu không, nhưng không đưa nó vào đối sánh.
  • một tùy chọn khác là tạo một số nhóm và đưa các nhóm đó vào thay thế: re.sub("([a-z])_([a-z])", r"\1'\2", s)
2 RyszardCzech Aug 17 2020 at 02:48

Khi sử dụng re.sub, văn bản cần giữ lại phải được chụp lại, văn bản cần xóa không nên.

Sử dụng

re.sub(r"([a-z])_(?=[a-z])",r"\1'",s)

Xem bằng chứng .

GIẢI TRÌNH

NODE                     EXPLANATION
--------------------------------------------------------------------------------
  (                        group and capture to \1:
--------------------------------------------------------------------------------
    [a-z]                    any character of: 'a' to 'z'
--------------------------------------------------------------------------------
  )                        end of \1
--------------------------------------------------------------------------------
  _                        '_'
--------------------------------------------------------------------------------
  (?=                      look ahead to see if there is:
--------------------------------------------------------------------------------
    [a-z]                    any character of: 'a' to 'z'
--------------------------------------------------------------------------------
  )                        end of look-ahead

Mã Python :

import re
s = "asdfasd a_b dsfd"
print(re.sub(r"([a-z])_(?=[a-z])",r"\1'",s))

Đầu ra:

asdfasd a'b dsfd
ShinNShirley Sep 30 2020 at 14:33

Ý re.submuốn thay thế mọi thứ nó phù hợp.

Có một cách tổng quát hơn để giải quyết vấn đề của bạn và bạn không cần phải sửa đổi lại biểu thức chính quy của mình.

Mã bên dưới:

import re


s = 'Data: year=2018, monthday=1, month=5, some other text'
reg = r"year=(\d{4}), monthday=(\d{1}), month=(\d{1})"


r = "am_replace_str"
def repl(match):
    _reg = "|".join(match.groups())
    return re.sub(_reg, r,match.group(0)) if _reg else r

# 
re.sub(reg,repl, s)

đầu ra: 'Data: year=am_replace_str, monthday=am_replace_str, month=am_replace_str, some other text'

Tất nhiên, nếu trường hợp của bạn không chứa các nhóm, mã của bạn có thể như thế này:

import re


s = 'Data: year=2018, monthday=1, month=5, some other text'
reg = r"year=(\d{4}), monthday=(\d{1}), month=(\d{1})"


r = "am_replace_str"
def repl(match):
    _reg = "|".join(match.groups())
    return re.sub(_reg, r,match.group(0))

# 
re.sub(reg,repl, s)