临时解决方案
这扩展了下面的“初始提供”并处理案例 1、2、5、6、8、9。它不处理有一个或多个完整的 <Name>…</Name> 条目以及起始 <Name> 的情况在同一行没有匹配的</Name>。坦率地说,我什至不知道如何开始处理这种情况。
未处理的案例 3、4、7 不是有效的 XML — 我也不相信它们是有效的 HTML(或 XHTML)。我相信它们可以通过与此处显示的完整<Name>…</Name> 版本类似(但更简单)的机制来处理。我将把它作为练习留给读者(注意字符类中的<——它需要变成/)。
script.sed
/<Name>/! b
/<Name>.*<\/Name>/{
: l1
s/\(<Name>[[:space:]]*\(X[X[[:space:]]*\)\{0,1\}\)[^X<[:space:]]\(.*[[:space:]]*<\/Name>\)/\1X\3/
t l1
b
}
/<Name>/,/<\/Name>/{
# Handle up to 4 lines to the end-name tag
/<\/Name>/! N
/<\/Name>/! N
/<\/Name>/! N
/<\/Name>/! N
# s/^/ZZ/; s/$/AA/p
# s/^ZZ//; s/AA$//
: l2
s/\(<Name>[[:space:]]*\(X[X[[:space:]]*\)\{0,1\}\)[^X<[:space:]]\(.*[[:space:]]*<\/Name>\)/\1X\3/
t l2
}
第一行“跳过”不包含<Name> 的行的处理(它们被打印并读取下一行)。接下来的 6 行是“初始报价”中的脚本,除了有一个 b 可以跳转到处理结束。
新部分是/<Name>/,/<\/Name>/ 代码。这会自行查找<Name>,并连接最多4 行,直到</Name> 包含在模式空间中。两个注释行用于调试——它们让我看到什么被视为一个单元。除了使用标签 l2 代替 l1 之外,其余部分与初始产品中的完全相同 - sed 正则表达式已经适应换行符。
这是重型sed 脚本,而不是我想要使用或维护的。我会选择使用 XML 解析器的 Perl 解决方案(因为我比 Python 更了解 Perl),但 Python 也可以使用适当的 XML 解析器来完成这项工作。
data
稍微扩展的数据文件。
<Name> Jason </Name>
<Name>Jim</Name>
<Name> Jason Bourne </Name>
<Name> Elijah </Name> <Name> Dennis </Name>
<Name> Elijah Wood </Name> <Name> Dennis The Menace </Name>
<Name>Elijah Wood</Name> <Name>Dennis The Menace</Name>
<Name> Jason
</Name>
<Name>
Jim</Name>
<Name>
Jim
</Name>
<Name> Jason
Bourne </Name>
<Name>
Jason
Bourne
</Name>
<Name> Elijah </Name>
<Name>
Dennis
</Name>
<Name> Elijah
Wood </Name>
<Name> Dennis
The Menace </Name>
<Name>Elijah
Wood</Name>
<Name>Dennis The
Menace</Name>
<Name> Jason </Name>
to
<Name> XXXXX </Name>
2. (see no space)
<Name>Jim</Name>
to
<Name>XXX</Name>
3.
<!--Name Jason /-->
to
<!--Name XXXXX /-->`
4.
<!--Name Jas /-->
to
<!--Name XXX /-->
starting tag, value and closing tag can all come in different line
5.
<Name>Jim
</Name>
to
<Name>XXX
</Name>
6.
<Name>
Jim
</Name>
to
<Name>
XXX
</Name>
7.
<!--Name
Jim
/-->
to
<!--Name
XXX
/-->
8.
<Name> Jason </Name> <Name> Ignacio </Name>
to
<Name> XXXXX </Name> <Name> XXXXXX </Name>
9.
<Name> Jason Ignacio </Name>
to
<Name> XXXXX XXXXXXX </Name>
or
<Name> XXXXXXXXXXXXX </Name>
没有声称data 文件包含最小的案例集;它是重复的。它包括来自问题的材料,除了像 <Name Value /> 这样的“非正统” XML 元素被转换为 XML cmets <!--Name Value /-->。映射实际上并不重要。开头部分与<Name> 不匹配(并且尾部与</Name> 不匹配),因此它们无论如何都不会被处理。
输出
$ sed -f script.sed data
<Name> XXXXX </Name>
<Name>XXX</Name>
<Name> XXXXX XXXXXX </Name>
<Name> XXXXXX </Name> <Name> XXXXXX </Name>
<Name> XXXXXX XXXX </Name> <Name> XXXXXX XXX XXXXXX </Name>
<Name>XXXXXX XXXX</Name> <Name>XXXXXX XXX XXXXXX</Name>
<Name> XXXXX
</Name>
<Name>
XXX</Name>
<Name>
XXX
</Name>
<Name> XXXXX
XXXXXX </Name>
<Name>
XXXXX
XXXXXX
</Name>
<Name> XXXXXX </Name>
<Name>
XXXXXX
</Name>
<Name> XXXXXX
XXXX </Name>
<Name> XXXXXX
XXX XXXXXX </Name>
<Name>XXXXXX
XXXX</Name>
<Name>XXXXXX XXX
XXXXXX</Name>
<Name> XXXXX </Name>
to
<Name> XXXXX </Name>
2. (see no space)
<Name>XXX</Name>
to
<Name>XXX</Name>
3.
<!--Name Jason /-->
to
<!--Name XXXXX /-->`
4.
<!--Name Jas /-->
to
<!--Name XXX /-->
starting tag, value and closing tag can all come in different line
5.
<Name>XXX
</Name>
to
<Name>XXX
</Name>
6.
<Name>
XXX
</Name>
to
<Name>
XXX
</Name>
7.
<!--Name
Jim
/-->
to
<!--Name
XXX
/-->
8.
<Name> XXXXX </Name> <Name> XXXXXXX </Name>
to
<Name> XXXXX </Name> <Name> XXXXXX </Name>
9.
<Name> XXXXX XXXXXXX </Name>
to
<Name> XXXXX XXXXXXX </Name>
or
<Name> XXXXXXXXXXXXX </Name>
$
首发
部分答案 - 但它说明了您面临的问题。处理问题中的案例 1 和 2,加上多词变化,您可以使用脚本:
script.sed
/<Name>.*<\/Name>/{
: l1
s/\(<Name>[[:space:]]*\(X[X[[:space:]]*\)\{0,1\}\)[^X<[:space:]]\(.*[[:space:]]*<\/Name>\)/\1X\3/
t l1
}
这是相当扭曲的,这是礼貌的。它查找<Name>,后跟零个或多个空格。后面可以跟\(X[X[[:space:]]*\)\{0,1\},这意味着X 出现0 次或1 次,后跟一系列X 或空格。所有这些都在替换中被捕获为\1。然后有一个不是X、< 或空格的字符,后跟零个或多个任意字符、零个或多个空格以及</Name>。中间的单个字符被 X 替换。整个替换重复,直到通过标签 : l1 和条件分支 t l1 不再匹配。所有这些都只在<Name> 和</Name> 的行上运行。
data
<Name> Jason </Name>
<Name>Jim</Name>
<Name> Jason Bourne </Name>
<Name> Elijah </Name> <Name> Dennis </Name>
<Name> Elijah Wood </Name> <Name> Dennis The Menace </Name>
<Name>Elijah Wood</Name> <Name>Dennis The Menace</Name>
<Name> Jason
</Name>
<Name>
Jim</Name>
<Name> Jason
Bourne </Name>
<Name> Elijah </Name> <Name> Dennis
</Name>
<Name> Elijah
Wood </Name> <Name> Dennis
The Menace </Name>
<Name>Elijah
Wood</Name> <Name>Dennis The
Menace</Name>
输出
$ sed -f script.sed data
<Name> XXXXX </Name>
<Name>XXX</Name>
<Name> XXXXX XXXXXX </Name>
<Name> XXXXXX </Name> <Name> XXXXXX </Name>
<Name> XXXXXX XXXX </Name> <Name> XXXXXX XXX XXXXXX </Name>
<Name>XXXXXX XXXX</Name> <Name>XXXXXX XXX XXXXXX</Name>
<Name> Jason
</Name>
<Name>
Jim</Name>
<Name> Jason
Bourne </Name>
<Name> XXXXXX </Name> <Name> Dennis
</Name>
<Name> Elijah
Wood </Name> <Name> Dennis
The Menace </Name>
<Name>Elijah
Wood</Name> <Name>Dennis The
Menace</Name>
$
请注意最后的替换部分。那条线会让人头疼。
我还没有弄清楚脚本将如何处理各种分割线的情况,除了它几乎肯定需要加入线,直到</Name> 被捕获。然后它会进行与已经显示的内容密切相关的处理,但需要在匹配的材料中允许换行符。