PC [Regex] Nhóm và lặp trong Search

Thảo luận trong 'Hướng dẫn chung' bắt đầu bởi tran ngoc anh, 6/8/21.

  1. tran ngoc anh

    tran ngoc anh Cử nhân

    Mình có trường hợp cụ thể như sau:
    • Ô search: (\d+)</h([123])>\s+<h\2\b[^>]*>
    • Ô replace: \1<span class="hiden">. </span><br/>
    Note: Tìm heading bị ngắt tại vị trí ngăn cách tiêu đề số và tiêu đề chữ, thay bằng một dấu chấm và thẻ break, nhưng "hiden" nó đi để nó chỉ hiện dấu chấm ngăn cách ở mục lục, hiển thị thông thường thì vẫn không thấy dấu chấm.

    (\d+)
    là tìm một số, </h([123])> là tìm </h1> hoặc </h2> hoặc </h3>, thay vì phải tìm bằng 3 câu lệnh khác nhau.

    Các bạn hãy chú ý vào cặp () tạo thành hai nhóm (\d+) ([123]), hai nhóm này khi thay thế sẽ tương ứng \1 \2 ở ô replace. Thường thì chúng ta nhóm ở ô search để giữ kết quả trả về ở ô replace theo thứ tự tương ứng, song \2 vẫn có tác dụng ở chính ô search, ví dụ <h\2\b[^>]*> sẽ tìm thấy <h1> hoặc <h1 class="..."> khi </h([123])> tìm thấy </h1>; <h2> hoặc <h2 class="..."> khi </h([123])> tìm thấy </h2>...

    Tóm lại\1 hay \2 có thể dùng cho cả ô search chứ không riêng ô replace. Vì ([123]) khá ngắn có thể không cần thiết phải \2 ngay sau đó làm gì, nhưng nếu ([123]) là một nhóm phức tạp hơn, vài ba chục ký tự chẳng hạn, \2 sẽ đóng vai trò lặp lại chính xác nhóm ([123]), sẽ giúp đọc hiểu câu lệnh tốt hơn.

     
    songuyento and machine like this.
  2. vinaguy

    vinaguy Lớp 11

    Bác có thể copy một mẫu bác muốn làm không? (để em có thể nắm rõ được ý bác muốn nhiều hơn). Em đọc cả đoạn của bác thì em đã hiểu ý bác muốn làm gì... nhưng thấy câu lệnh của bác rối thiệt á... Đối với một số bác mới vào nghề chắc sẽ không thể nào mò ra được ý nghĩa dòng lệnh. Và hình như Ô replace còn thiếu cấu tử hay sao á bác nhỉ?
     
    machine thích bài này.
  3. tran ngoc anh

    tran ngoc anh Cử nhân

    @vinaguy Đây là một đoạn minh họa:

    <p><i>Báo cáo chính trị của Ban chấp hành trung ương, diễn văn kết thúc cuộc thảo luận bản báo cáo, báo cáo về việc sửa đổi cương lĩnh và thay đổi tên đảng, những bản tham luận và đề nghị</i> – <i>in theo đúng bản in trong cuốn sách xuất bản năm 1928, có đối chiếu với bản tốc ký, với các bản ghi chép của thư ký và bản in trong cuốn sách xuất bản năm 1923; bổ sung vào nghị quyết về chiến tranh và hòa bình và bản nghị quyết về vấn đề “những người cộng sản cánh tả” từ chối tham gia Ban chấp hành trung ương</i> – <i>theo các bản thảo</i></p>

    <h2 id="toc_1">1</h2>

    <h2 id="toc_2">BáO CáO CHíNH TRị CủA BAN CHấP HàNH TRUNG ưƠNG NGàY 7 THáNG BA</h2>

    <p>Đáng lẽ bản báo cáo chính trị có thể là bản kê những biện pháp của Ban chấp hành trung ương, nhưng điều bức thiết trong lúc này, không phải là một bản báo cáo như thế, mà là một <i>bả n trì nh bà y khái quát về toà n bộ cuộc cách mạng của chúng ta;</i> chỉ có một bản trình bày như thế mới có thể luận chứng một cách duy nhất mác-xít tất cả các nghị quyết của chúng ta. Chúng ta phải xem xét toàn bộ tiến trình phát triển trước đây của cách mạng và làm sáng tỏ vì sao bước phát triển về sau của cách mạng đã thay đổi. Trong cuộc cách mạng của chúng ta, có những bước ngoặt sẽ có ý nghĩa rất lớn đối với cách mạng thế giới, bước ngoặt đó chính là <i>Cách mạng tháng Mười.</i> </p>
    Bạn bỏ đoạn này vô calibre editor rồi dùng câu lệnh phía trên test thử xem ^_^ với hình minh họa mình để bên dưới nhìn sẽ dễ hiểu hơn :D

    [​IMG]

    [​IMG]
     
    machine and vinaguy like this.
  4. tran ngoc anh

    tran ngoc anh Cử nhân

    Mình muốn các bạn tập trung vào nhóm ([123]) trong </h([123])> và đặc biệt là \2 với chức năng thay thế cho nhóm ([123]) ở một cụm khác trong ô search, vì thường \2 được dùng ở ô replace nhiều hơn, thread này mình muốn truyền tải là nó cũng có thể dùng ở ô search.

    Vốn câu lệnh ban đầu sẽ là (\d+)</h[123]>\s+<h[123]\b[^>]*>, nhưng nếu chúng ta có 100 level thì sao :D [123456789..............] và lại lặp lại ở nhiều cụm trong câu lệnh thì sao, giải pháp chính là nhóm nó lại thành ([123456789..............]) và \2 nó là xong, gọn nhẹ hơn rất nhiều.

    Chú ý là đầu câu lệnh có (\d+) đã là \1 rồi, nên ([123]) sẽ là \2. Vị trí của nhóm trong câu lệnh sẽ quyết định con số sau dấu gạch nghiêng "\".

    Về vị trí thì cần chú ý như sau nữa:
    (<h([12])\b[^>]*>.+?)(</h\2>)\s+<p\b[^>]*>(.+?)</p>
    • (<h([12])\b[^>]*>.+?) = \1
    • ([12]) = \2
    • (</h\2>) = \3
    • (.+?) = \4
     
    machine and vinaguy like this.
  5. vinaguy

    vinaguy Lớp 11

    Em thì hay làm như này nè bác @tran ngoc anh (xem phía dưới). Có thể câu lệnh hơi dài 1 chút nhưng đảm bảo với bác là không bao giờ sai luôn và nhìn cấu trúc câu cũng "nhìn phát hiểu ngay". Vụ này em làm nhiều rồi (bác mổ mấy cuốn sách của em ra là thấy). Chỉ gặp khó một điều là các sách trước đây được làm thì đề mục nó không thống nhất. Lúc nó thế này, lúc nó thế kia... nên lúc replace all là nó sẽ sót lại những em hơi "khác khác" tí đó.
    Ví dụ trên của bác:
    <h2 id="toc_1">1</h2>

    <h2 id="toc_2">BáO CáO CHíNH TRị CủA BAN CHấP HàNH TRUNG ưƠNG NGàY 7 THáNG BA</h2>
    Câu trên chuyển thành cấu trúc như sau:

    Ô FIND:
    <h(.*?)>(.*?)</h(.*?)>

    <h(.*?)>(.*?)</h(.*?)>

    Ô REPLACE:
    <h\1>\2<span class="hiden">. </span><br/>\5</h\6>

    Thế là xong và nhìn đỡ rối hơn á bác. Cấu trúc trên em cần giữ lại cụm 1,2 và 5,6 nhé các bác (câu ghi chú này có thể bác @tran ngoc anh hiểu rồi, nhưng các bác newbie khác thì sẽ phải xem thêm ở đây)
    Lưu ý: Trước khi chạy các replace all các bác nên tuốt lại bằng "Bông Hoa" ở trong Tool trước nhé để đảm bảo mọi thứ tương đồng.
     
    machine and tran ngoc anh like this.
  6. tran ngoc anh

    tran ngoc anh Cử nhân

    @vinaguy Ok bạn, hồi mình mới làm quen với regex cũng chỉ với \d và .*? là xử ngon epub rồi ^_^

    À mà câu trên của bạn chỉ cần đổi lại một chút là khỏi cần bấm "làm đẹp" nó vẫn chạy ngon lành: <h(.+?)>(.+?)</h(.+?)>\s+<h(.+?)>(.+?)</h(.+?)>

    \s+ là một khoảng trắng hoặc nhiều khoảng trắng, hoặc một khoảng xuống dòng hoặc nhiều khoảng xuống dòng, bao tất cả các trường hợp.

    .+? bằng với .*? mà mình cứ thấy gõ .+? các phím gần nhau hơn thấy tiện nên thích dùng hơn :D
     
    machine and vinaguy like this.
  7. vinaguy

    vinaguy Lớp 11

    Em kết quả /s+ này rồi đó bác... Nó làm khổ em bấy lâu nay :)
     
    tran ngoc anh thích bài này.
  8. vinaguy

    vinaguy Lớp 11

    Em có chút mắc míu như sau mà chưa gỡ ra nè các bác:
    Em muốn tìm: Ví dụ:
    <aside>bla bla bla
    <p>bla bla bla</p>
    vân vân
    <p>bla bla bla</p>
    <p>bla bla bla</p>
    </aside>
    Viết câu lệnh như thế nào các bác? Giúp em với. Cái này hữu ích ghê gớm trong quá trình chỉnh sửa các định dạnh cũ trước đây mà giờ ít phù hợp hoặc bị rườm ra (ví dụ: sửa đoạn thơ, sửa đoạn format gì gì đó, sửa đoạn chú thích... vân vân).
    Quan trọng là viết cho máy hiểu được cái Vân Vân kia kìa.
    Ai có sáng kiến giúp em với nhóe.
     
    Chỉnh sửa cuối: 7/8/21
  9. tran ngoc anh

    tran ngoc anh Cử nhân

    Đây bạn:

    Calibre
    [​IMG]

    Sigil:
    [​IMG]
     
    machine and vinaguy like this.
  10. vinaguy

    vinaguy Lớp 11

    OK thanks bác @tran ngoc anh. Vậy mà xưa giờ em không biết... nên toàn phải làm ra 3-4 bước lâu như cái gì luôn á bác. Làm kiểu này thì tiện và chính xác biết bao nhiêu.
    Lỗi do mình không đọc kỹ hướng dẫn khi sử dụng :)
     
  11. tran ngoc anh

    tran ngoc anh Cử nhân

    Nhưng dùng cẩn thận nha :D tốt nhất là Replace and Find next cho chắc, Replace All mà phát sinh lỗi là khó dò lại để sửa lắm. Vì file ít khi đồng nhất về định dạng, mỗi dạng Replace All đều tiềm ẩn rủi ro không giống nhau, một khi Replace All là phải chấp nhận bỏ time ra mà debug ^_^
     
    vinaguy thích bài này.
  12. tran ngoc anh

    tran ngoc anh Cử nhân

    Cảm thấy bất an với <h.*?> của bạn lắm, nó sẽ tìm cả các thẻ <head>, <header>, <html>, <hr> rất là nguy hiểm nếu muốn đảm bảo replace all mà không lỗi :D

    Tốt nhất vẫn là xác định chính xác các level của heading bằng <h[1234]\b, 4 số level heading trong [] có nghĩa là tìm một trong 4 số đó, để đảm bảo phía sau nó không đi liền bởi "e" hoặc "t" hoặc "r" của các thẻ <head>, <header>, <html>, <hr>.

    Sau đó thêm [^>]*> nữa để tìm các trường hợp thẻ có định dạng class hay id mục lục, ví dụ <h1 class="h1"> hoặc <h2 id="toc_2">
    • [^>] là loại trừ trường hợp theo sau số level là dấu đóng thẻ >, mục đích là tìm các trường hợp có class và id,
    • * có nghĩa là 0 lần xuất hiện hoặc rất nhiều lần xuất hiện của [^>], có nghĩa là regex sẽ tìm tất cả các h1 h2 h3 h4 class lẫn không có class.
    Túm lại : <h[1234]\b[^>]*> sẽ chỉ tìm chính xác tất cả các thẻ heading mà không lẫn vào <head>, <header>, <html>, <hr>...

    Song: Nếu là <h(.+?)>(.+?)</h(.+?)>\s+<h(.+?)>(.+?)</h(.+?)> thì với hai dòng cùng 4 thẻ h như này thì cũng khó để mà regex nó nhầm được :D nên là vẫn dùng tốt.
     
    machine and vinaguy like this.
  13. vinaguy

    vinaguy Lớp 11

    Đúng rồi bác @tran ngoc anh. Mình phải tùy trường hợp mà dùng để hạn chế nó lại kẻo nó bắt nhầm chớ. Nếu bác sợ bắt nhầm thì bác uýnh:
    <h(\d+)(.*?)>
    Thế này thì nó đâu có nhầm được bác nhễ?
    Nhớ là tên nhóm giờ đã thay đổi rồi bác nhé.
     
    machine and tran ngoc anh like this.
  14. tran ngoc anh

    tran ngoc anh Cử nhân

  15. tran ngoc anh

    tran ngoc anh Cử nhân

    đơn giản hiệu quả phết luôn ^^
     
    vinaguy thích bài này.
  16. vinaguy

    vinaguy Lớp 11

    Với em việc sửa sách bây giờ thì cụm (\d+) - "tìm bất cứ số nào" và cụm (.*?) - "tìm bất cứ thứ gì" - trở thành chủ đạo luôn rồi đó bác.
    Lúc đầu em mới đọc cụm (.*?) "tìm bất cứ thứ gì"... em phì cười ra và nghĩ... Cái bọn Calibre này dở hơi, chắc chúng nó bị gì rồi? Tại sao lại cho người ta cái cách "tìm bất cứ thứ gì" thế thì tìm để làm gì nữa... nhưng sau này, em mới thấy hiệu quả của nó mới cao cả làm sao :)
     
  17. tran ngoc anh

    tran ngoc anh Cử nhân

    Mình thì vẫn thấy thiếu thiếu ^_^
     
    Chỉnh sửa cuối: 7/8/21

Chia sẻ trang này