【问题标题】:Lookahead for the usage of local bookmark and replace local bookmark with the content of bookmark预知本地书签的使用,将本地书签替换为书签的内容
【发布时间】:2016-03-24 00:19:02
【问题描述】:

我是正则表达式的新手,还在学习。

我有一个 XML 文件,其中有一个文本节点,后面是临床信息。

在文本节点中,我定义了类似的内容 ID

<item>
    <content ID="a138134600007">Wellbutrin TABS;</content>
    <content ID="a138134600007-sta"> (Active) </content>
    <content ID="a138134600007-comments"> </content>
</item>

稍后在包含实际临床数据的较低 xml sn-p 中引用这些 id

              <text>
                <reference value="#al38134600007" />
              </text>

我想用 id 表示的内容替换上面的文本节点,所以我想将文件转换为如下所示

              <text>
                Wellbutrin TABS;
              </text>

作为一名 Java 开发人员,我拒绝编写一个非常丑陋的解决方案并寻找一个更优雅的正则表达式解决方案(更不用说性能,因为转换需要在半百万个 xml CCD 中发生)。

我想用 perl 来做,因为它在 linux 上默认可用,但很高兴使用任何可以解决这个问题的技术。

有什么建议吗?

提前致谢, 干杯, 维平。

【问题讨论】:

  • 解析 XML 时,优雅的解决方案通常是不使用正则表达式 :-) stackoverflow.com/questions/701166/…
  • 用文本解析 xml 不是一个好主意,他们有 xml 解析器
  • 我们无法针对 GIF 测试可能的解决方案。包括一个小的、完整的、可测试的示例输入和预期输出示例。
  • 请不要发布代码图片的链接;只需发布代码,特别是因为它很少。你能相应地编辑你的问题吗?
  • “作为一名 Java 开发人员,我拒绝编写一个非常丑陋的解决方案” 我不同意这两者有任何关联

标签: regex perl awk sed regex-lookarounds


【解决方案1】:

您可以使用 XML::LibXML 轻松实现相同的目标,并且比使用几乎无法处理特殊字符、转义序列、新行和类似内容的正则表达式更可靠:

my $doc = XML::LibXML->load_xml(IO => \*STDIN); # or stream or file..
foreach my $node ($doc->documentElement()->findnodes("/path/to/your/element/text/reference")) {
    $node->parentNode()->appendText(yourLookupMethod($node->getAttribute("value"));
    $node->unbindNode();
}
$doc->toFH(\*STDOUT, 0); # or stream or file...

【讨论】:

  • 同意,但由于我是一名优秀的 Java 程序员,我想如果我使用 DOM 还不如使用 Java DOM。
  • @driftingprogrammer : 当然,除了真正的 XML 解析器之外的任何语言 :-) 但是这里的 Perl 为简单起见 :-)
【解决方案2】:

因为提问者要求它:在一些假设下,一个简单的正则表达式就可以做到。

假设文件没有 XML 语法错误,&lt;content&gt; 标签只能在 &lt;item&gt; 标签内找到,空格的使用和属性的顺序在整个 XML 中是一致的,即它是自动生成的,@ 987654326@ 标记和子项正好覆盖三行,并且 xml 看起来与问题中的示例相同:

项目/内容节点

          <item>
            <content ID="a1234"> text </content>
            <!-- more -->
          </item>

文本节点

          <text>
            <reference value="#a1234" />
          </text>

Perl 代码:

根据问题替换标签。它处理并打印出不受干扰的标签,而不是我们要替换的标签。 (&lt;reference&gt;)。

项目/内容标签的正则表达式:/&lt;content ID="(.*?)"&gt;(.*?)&lt;\/content&gt;/

文本/参考标签的正则表达式:s/(&lt;text&gt;\s*)&lt;reference value="#(.*?)" \/&gt;(\s*&lt;\/text&gt;)/$1.$content{$2}.$3/es

进行替换的第二个正则表达式从之前填充的 %content 哈希中获取值。

my %content;

## open filehandles called XIN, XOUT

## stores 3 lines from file, used by second loop
my @block;

while (<XIN>) {
  if (/<content ID="(.*?)">(.*?)<\/content>/) {
    my ($id, $text) = ($1, $2);
    $content{$id} = $text;
  } elsif (/<text>/) {
    ## keep this line for next loop
    push @block, $_;
    ## when we start seeing <text> tags, go to next loop for these
    last;
  }
  print XOUT $_;
}

while (1) {
  ## read up to 3 lines into @block
  for (scalar(@block)+1..3) { my $l = <XIN>; last if (!defined $l); push @block, $l; }
  ## if we've read nothing, we are at EOF
  last if (scalar(@block) == 0);

  my $concat = join '', @block;
  if ( ($concat =~ s/(<text>\s*)<reference value="#(.*?)" \/>(\s*<\/text>)/$1.$content{$2}.$3/es) > 0) {
      print XOUT $concat;
      @block = ();
  } else {
      print XOUT shift @block;
  }
}

否则,只需使用 XML 解析器。它有很多 CPAN 模块。我喜欢XML::Parser。它不需要将整个文件加载到内存中。

complete perl script

hypothetical input xml

output xml

附:可能不适合假设的一件事是 &lt;content&gt; 标签只能在 &lt;item&gt; 标签内找到。但这是一个简单的改变。如果 OP 提供详细信息,将更新。

P.S.S 正则表达式 很简单;)。逻辑比较长。如果输入的 XML,包括没有特别提到的标签,不需要保留,那就更简单了。

【讨论】:

  • 非常感谢我最终按照大家的建议使用了 Java DOM,但非常感谢您提供答案,我绝对将它用作学习工具。
【解决方案3】:

我建议查看Java's XML Parsing。正如很多人所说,不要使用 Regex 来解析 XML 文件。

您也可以使用 xmlint(带有 xpath)。我还建议在此处发布示例 XML 文件而不是 GIF img

【讨论】:

  • XML不符合xsd所以不能使用jaxb,不确定Perl XML解析器是否需要xsd验证...
  • 最终使用 Java DOM,就像其他人一样,你是对的,最好不要使用 Regex 进行 XML 解析。
猜你喜欢
  • 1970-01-01
  • 2015-10-19
  • 2015-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-23
  • 1970-01-01
  • 2021-03-22
相关资源
最近更新 更多