【问题标题】:Sed - conditional branching within an address rangesed - 地址范围内的条件分支
【发布时间】:2025-12-03 09:15:01
【问题描述】:

我需要从一些原始文本数据格式化一个批量输入文件。我能够使用Sed 实现我的大部分解决方案,这是首选,但不是绝对必需的(我只想坚持使用这个工具)。当我疯狂地尝试解析 [大量] 以下输入时,问题变得清晰起来:

---- Start Product ----
PartNumber>> 123457
Size04_Req>> 2 
Size02_Req>> 1 
PartColor>> Natural
PartDescription>> Guys Tee 
---- End Product ----
---- Start Product ----
PartNumber>> TPIOO9205
Size05_Req>> 1 
PartColor>> Natural
PartDescription>> Black Hoodie


---- End Product ----


###...with the objective of achieving the following output:


---- Start Product ---
PartNumber>> 123457
Size01_Req>> 0 
Size03_Req>> 0 
Size05_Req>> 0 
Size06_Req>> 0
Size04_Req>> 2 
Size02_Req>> 1 
PartColor>> Natural
PartDescription>> Guys Tee
---- End Product ----
---- Start Product ----
PartNumber>> TPIOO9205
Size01_Req>> 0 
Size02_Req>> 0 
Size03_Req>> 0 
Size04_Req>> 0 
Size06_Req>> 0
Size05_Req>> 1 
PartColor>> Natural
PartDescription>> Black Hoodie
---- End Product ----

我相信这就像在地址范围内工作一样简单 /----\ Start\ Product\ ----/,/----\ End\ Product\ ----/ 并做一些优雅的分支和 :label 工作,但显然,我的倾向是跳上 awk 或类似的逻辑 - 因为我要疯了 - 也许使用另一个工具会更容易为达到这个。然而,我坚持我最初的愿望是留在 Sed,而且因为我喜欢每天学习一个新的 Sed 技巧,这怎么可能呢?请注意,逻辑是插入 SizeXX_Req>> 0 用于未考虑的尺寸 01-06,顺序并不重要,这就是为什么我认为 Sed 甚至可以得到最后一点部分完成了半理智。每个开始/最终产品部分之间总是至少有一个 SizeXX_Req 行。任何 Sed(i) 大师都能快速解决这个问题吗?我是否只是从最近写的大量正则表达式中脱颖而出,错过了一个简单的修复方法?

前进。用另一种 Rando 语言给我看,甚至不用解释你是如何(或为什么)这样做的,我也对此感到失望。预先感谢,窥视。

【问题讨论】:

  • 修复丢失的位,我认为,超出了sed(或者,无论如何,超出了理智的sed,或者只是有点疯狂的sed)。使用完整的编程语言会做得更好 — awk, perl, python, ...
  • 复杂的逻辑总是在其他工具中得到很好的呈现:awk 甚至使用脚本语言从头开始。在这种情况下,我不会更喜欢 sed。
  • 那么它确实超出了在 Sed 中可以完成的事情吗?在我看来是这样,但我想也许我只是在使用 Sed 而不是 Sed 本身达到了我个人技能的界限。只是因为 :labels 和分支似乎,好吧,它们可以变得“深”,嘿,你知道吗? [f] awk 它,我会的。但是我仍然会被一些 Sed 诡计逗乐>:-) 有人想在我换档时放下 awk 吗?随意!

标签: parsing loops sed branch labels


【解决方案1】:

对我来说,仅使用 sed 似乎是不可能的,因为您需要一个计数器和某种反向引用。也许我错了,无论如何,使用 Perl:

use warnings;
use strict;

my (%sizes, %part);
while(<>) {
  if (/^---- End Product ----/) {
    print "---- Start Product ----\n";
    print "PartNumber>> $part{Number}\n";
    for my $size (map { sprintf "%02d", $_ } 1..6) {
      if (not defined $sizes{$size}) {
        print "<b>Size${size}_Req>> 0</b>\n";
      }   
    }   
    for my $size (keys %sizes) {
      print "Size${size}_Req>> $sizes{$size}\n";
    }   
    print "Part$_>> $part{$_}\n" for ("Color", "Description");
    print "---- End Product ----\n";
    %sizes = (); 
    %part  = (); 
  }
  $sizes{$1} = $2 if (/^Size(\d+)_Req>>\s*(\d+)/);
  $part{$1} = $2 if (/^Part(\w+)>> (.*)/);
}

使用

perl script.pl input

输出

---- Start Product ----
PartNumber>> 123457
<b>Size01_Req>> 0</b>
<b>Size03_Req>> 0</b>
<b>Size05_Req>> 0</b>
<b>Size06_Req>> 0</b>
Size04_Req>> 2
Size02_Req>> 1
PartColor>> Natural
PartDescription>> Guys Tee 
---- End Product ----
---- Start Product ----
PartNumber>> TPIOO9205
<b>Size01_Req>> 0</b>
<b>Size02_Req>> 0</b>
<b>Size03_Req>> 0</b>
<b>Size04_Req>> 0</b>
<b>Size06_Req>> 0</b>
Size05_Req>> 1
PartColor>> Natural
PartDescription>> Black Hoodie
---- End Product ----

【讨论】:

  • 感谢@perreal - 这就像一个魅力。如果没有 Sedophiles 插话,最好有一个解决方案。但是我将不回答它,看看 Sed 是否通过!干杯!