Thêm văn bản giữa nhiều dòng với sed nếu dòng trước đó không khớp với mẫu


1

Tôi đang vật lộn để thêm <dl>các thẻ xung quanh một danh sách định nghĩa với sed và có lẽ có một cách dễ dàng hơn để làm điều đó (tôi rất muốn biết).

Tôi muốn tìm kiếm một tập tin cho bất kỳ dòng nào có chứa một <dt>, nhưng chỉ khớp nếu dòng trước đó không chứa <dt>hoặc <dd>. Khi một trận đấu được tìm thấy, chèn một <dl>.

Nỗ lực của tôi cho đến nay (hoàn toàn không phù hợp):

sed '/^((?!<dt>).)*$/ {
    N
    /<dt>/ {
        s/<dt>/<dl><dt>/
    } 
}' file

Và tập tin

# TODO #

 * Set up mail transfer agent
 * Reconfigure timezone

```bash
dpkg-reconfigure tzdata
```

# Hardware #
  <dt>RAM</dt>
  <dd>2GB</dd>

# Partitions #

<dt>`/dev/sda1`</dt>
<dd>/boot</dd>
<dt>`/dev/sda2`</dt>
<dd>/</dd>

Mục đích của tất cả những điều này là để viết một trình phân tích cú pháp chuyển đổi đánh dấu wiki moinmoin thành đánh dấu, để chuyển sang một công cụ wiki mới. Danh sách định nghĩa hiện được thực hiện theo quy tắc sau:

sed -i 's/^ \(.*\):: \(.*\)$/  <dt>\1<\/dt>\n  <dd>\2<\/dd>/' file

Tôi muốn đầu ra trông như thế này:

# TODO #

 * Set up mail transfer agent
 * Reconfigure timezone

```bash
dpkg-reconfigure tzdata
```

# Hardware #
<dl>
  <dt>RAM</dt>
  <dd>2GB</dd>
</dl>

# Partitions #

<dl>
<dt>`/dev/sda1`</dt>
<dd>/boot</dd>
<dt>`/dev/sda2`</dt>
<dd>/</dd>
</dl>

Lưu ý rằng tôi muốn html hợp lệ càng nhiều càng tốt. Cần phải có một thẻ đóng cho mỗi thẻ mở.


ok, nhưng tất cả các dòng của bạn phù hợp với mô hình. Có cách nào bạn có thể cung cấp (chỉ một chút) đầu vào ví dụ thực tế hơn và để bổ sung cho nó bằng một ví dụ về đầu ra mong muốn của bạn không? nó chỉ làm cho nó đơn giản hơn - ít đoán hơn.
mikeerv 8/12/2015

1
Tôi đã mở rộng tệp ví dụ - xin lỗi về điều đó.
stooj 8/12/2015

Vì vậy, bạn nên bọc mỗi cặp <dt>...</dt>\n<dd>...</dt>\nthẻ tuần tự trong một cặp khác <dl>...</dl>hoặc toàn bộ một chuỗi các cặp được bao quanh?
mikeerv

Một chuỗi các cặp nên được đính kèm. Tôi đã thêm đầu ra mong muốn dưới dạng bản demo.
stooj

Câu trả lời:


3

Điều này có thể nhiều sedhơn bạn mong đợi, nhưng tôi nghĩ đây là cách tốt nhất để thực hiện những gì bạn muốn với sed.

Kịch bản này:

  • Chèn một dòng <dl>trước mỗi dòng có chứa một <dt>, nếu không có khác <dt>, <dd>hoặc <dl>trước dòng.

  • Nối một dòng </dl>sau mỗi dòng chứa <dd>, nếu dòng sau dòng chứa <dd>không chứa <dd>.

sedKịch bản lệnh này sử dụng sed holdkhoảng trắng để ghi nhớ dòng trước đó để có thể kiểm tra các <d[tdl]>thẻ trước khi chèn <dl>thẻ. Nó cũng sử dụng địa chỉ tương đối ADDR,+Nđể cho phép thêm </dl>thẻ đóng . Một trường hợp đặc biệt được yêu cầu để phát hiện nếu a <dd>nằm trên dòng cuối cùng của tệp và cần được nối thêm </dl>. Kiểm tra ( tT) và phân nhánh ( b) được sử dụng rộng rãi để thực hiện logic.

#!/bin/sh

sed '
    /<dt>/ {
        x                  # exchange pattern and hold space
        s/<d[tdl]>//       # subsitutue, just testing for pattern
        g                  # copy hold space back, overwriting pattern space
        t end              # branch to :end if previous subsitution successful
        i \
<dl>
    }

    $ {
        /<dd>/ ! b end     # if <dd> on last line, append </dl>
        a \
</dl>
    }

    /<dd>/,+1 {            # on each line containing <dd> and the line after
        /<dd>/ b end       # if does not contain <dd>, insert </dl>
        i \
</dl>
    }

:end
    h                      # copy pattern space to hold space for next round

' "$@"

Kịch bản lệnh này sửa đổi dữ liệu mẫu trông như thế này:

[...]

# Hardware #
<dl>
  <dt>RAM</dt>
  <dd>2GB</dd>
</dl>

# Partitions #

<dl>
<dt>`/dev/sda1`</dt>
<dd>/boot</dd>
<dt>`/dev/sda2`</dt>
<dd>/</dd>
</dl>

à! Thế là quấn hết đường rồi! Bạn sẽ làm gì nếu bạn có một <dt>...</dt>cặp có vị trí hợp lệ nhưng không được theo sau bởi một <dd>...</dd>cặp có vị trí hợp lệ ?
mikeerv

Kịch bản này như được viết sẽ không đưa ra </dl>ngoại trừ sau a <dd>.
RobertL

Điều đó có thể đúng - tôi không biết. Tôi sẽ xem xét nó đúng hơn so với cách khác - nhưng tôi không biết làm thế nào tất cả các công cụ thẻ đó hoạt động. đó là lý do tại sao tôi hỏi (bạn và người hỏi) - tôi muốn làm một câu trả lời. cảm ơn bạn. Oh. nhưng - tốt - bạn có nghĩa là bạn có thể làm <dl>mà không có </dl>? tôi không biết về điều đó .... hm. tốt. bạn đã nhận được phiếu bầu của tôi nào. con vịt trong thực tế - tôi thậm chí đã không cân nhắc sự phân nhánh của điều đó - chỉ là tôi không biết liệu có </dl>nên đi trước dấu vết không <dt>...
mikeerv

2
Các thẻ là <dl>: danh sách <dt>định nghĩa, thuật ngữ <dd>định nghĩa , dữ liệu định nghĩa (hoặc định nghĩa). Tôi nghĩ rằng họ muốn bọc các <dt>/<dd>trình tự với <dl>. Trên các đoạn htmltrong wiki, chúng ta không thực sự cần phải quá quan tâm đến xml/htmlbối cảnh / tính hợp lệ lớn hơn . Vì vậy, tôi viết kịch bản này cho dữ liệu đầu vào đã cho. Nếu có một trường hợp <dt>không được chấp nhận <dd>, điều đó sẽ yêu cầu thay đổi, mặc dù điều đó hoàn toàn có thể thực hiện được. Nếu câu trả lời xử lý các trường hợp không có trong dữ liệu mẫu, tôi nghĩ nó quá phức tạp và khó hiểu. Tôi hy vọng điều đó sẽ giúp.
RobertL

Nổi bật. Cảm ơn các ý kiến ​​là tốt, tôi không có ý tưởng về điều chi nhánh trong sed.
stooj
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.