【问题标题】:How to extract text sections into separate files named based on id?如何将文本部分提取到基于 id 命名的单独文件中?
【发布时间】:2019-10-05 17:05:48
【问题描述】:

给定一个包含一系列重复文本部分的文本文件,我应该如何提取这些部分并将它们存储在名称来自每个部分的 id 的单个文本文件中?

  • 所有部分都以<?xml 开头,以</svg> 结尾。
  • 所有部分都有一个 ID 标签,应作为其名称的基础。

我不确定如何在 for loop 中组合两个 sed 正则表达式来实现这一点。


原始.svg:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="France" width="1500" height="1000" viewBox="0 0 3 2">
<rect width="3" height="2" fill="#009246"/>
<rect width="2" height="2" x="1" fill="#fff"/>
<rect width="1" height="2" x="2" fill="#ce2b37"/>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Italy" width="900" height="600">
<rect width="900" height="600" fill="#ED2939"/>
<rect width="600" height="600" fill="#fff"/>
<rect width="300" height="600" fill="#002395"/>
</svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Ireland" width="1200" height="600">
<rect fill="#169b62" width="1200" height="600" />
<rect fill="#fff" x="400" width="800" height="600" />
<rect fill="#ff883e" x="800" width="400" height="600" />
</svg>

结果:

France.svg:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="France" width="1500" height="1000" viewBox="0 0 3 2">
<rect width="3" height="2" fill="#009246"/>
<rect width="2" height="2" x="1" fill="#fff"/>
<rect width="1" height="2" x="2" fill="#ce2b37"/>
</svg>

意大利.svg:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Italy" width="900" height="600">
<rect width="900" height="600" fill="#ED2939"/>
<rect width="600" height="600" fill="#fff"/>
<rect width="300" height="600" fill="#002395"/>
</svg>

爱尔兰.svg:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Ireland" width="1200" height="600">
<rect fill="#169b62" width="1200" height="600" />
<rect fill="#fff" x="400" width="800" height="600" />
<rect fill="#ff883e" x="800" width="400" height="600" />
</svg>

【问题讨论】:

  • SO 是专为专业和热情的程序员准备的问答页面。将您自己的代码添加到您的问题中。您应该至少展示自己为解决这个问题所做的研究。
  • 任何时候你发现自己正在考虑一个解决方案,two sed REGEXes would need to be combined within a for loop 停下来并意识到你已经偏离了轨道,因为这绝不是解决任何问题的最佳解决方案。

标签: xml shell loops svg sed


【解决方案1】:

使用 bash 和 xmlstarlet:

#!/bin/bash

while read -r line; do

  # fill variable with all lines and append newline to every line
  svg="$svg$line"$'\n'

  # last line?
  if [[ $line =~ \</svg\> ]]; then

    # extract attribute from xml
    svgfile=$(xmlstarlet select -N x='http://www.w3.org/2000/svg' --template --value-of '//x:svg/@id' <<< "$svg")

    # remove trailing newline and output xml to new file
    echo -e "${svg:0:-1}" > "${svgfile}.svg"

    unset svg
  fi
done < Original.svg

【讨论】:

    【解决方案2】:

    使用 GNU awk for multi-char RS 将文件分成每个 SVG 部分的有效 XML,协同处理让我们将记录打印到 xmlstarlet 并读取输出,第二个 arg 到 close() 让我们关闭管道到 xmlstarlet 以便它处理输入,而 xmlstarlet 实际读取 XML:

    $ cat ../tst.awk
    BEGIN {
        RS  = "</svg>[[:space:]]*"
        ORS = ""
        xmlParser = "xmlstarlet select -N x=\047http://www.w3.org/2000/svg\047 --template --value-of \047//x:svg/@id\047"
    }
    RT != "" {
        $0 = $0 RT
    
        print |& xmlParser
        close(xmlParser,"to")
    
        if ( (xmlParser |& getline id) > 0 ) {
            print > (id ".svg")
        }
        close(xmlParser)
    }
    

    例如,file 包含来自问题的输入文本:

    $ ls
    file  tst.awk
    
    $ awk -f tst.awk file
    
    $ ls
    file  tst.awk  France.svg  Ireland.svg  Italy.svg
    
    $ tail -n +1 *.svg
    ==> France.svg <==
    <?xml version="1.0" encoding="UTF-8"?>
    <svg xmlns="http://www.w3.org/2000/svg" id="France" width="1500" height="1000" viewBox="0 0 3 2">
    <rect width="3" height="2" fill="#009246"/>
    <rect width="2" height="2" x="1" fill="#fff"/>
    <rect width="1" height="2" x="2" fill="#ce2b37"/>
    </svg>
    
    ==> Ireland.svg <==
    <?xml version="1.0" encoding="UTF-8"?>
    <svg xmlns="http://www.w3.org/2000/svg" id="Ireland" width="1200" height="600">
    <rect fill="#169b62" width="1200" height="600" />
    <rect fill="#fff" x="400" width="800" height="600" />
    <rect fill="#ff883e" x="800" width="400" height="600" />
    </svg>
    
    ==> Italy.svg <==
    <?xml version="1.0" encoding="UTF-8"?>
    <svg xmlns="http://www.w3.org/2000/svg" id="Italy" width="900" height="600">
    <rect width="900" height="600" fill="#ED2939"/>
    <rect width="600" height="600" fill="#fff"/>
    <rect width="300" height="600" fill="#002395"/>
    </svg>
    

    如果&lt;/svg&gt; 位于注释或字符串中,并且可能在您似乎没有的其他上下文中,它将失败。如果 XML 部分中没有 id,那么您想做什么,所以如果发生这种情况,我只是不打印 XML。

    【讨论】:

      【解决方案3】:

      这是一个脆弱但可移植的 awk 解决方案。

      awk '
                  {a[i++]=$0}
        /^<svg/   {for(f=1; f<=NF; f++) if($f~/^id=/) split($f, id, /["=]+/)}
        /^<\/svg/ {for(n=0; n<i; n++) print a[n] > (id[2] ".svg"); i=0}
      ' Original.svg
      
      1. 将每一行放入以增量为索引的数组中
      2. 在以&lt;svg 开头的行中,使用一个或多个等号或双引号将第三个字段拆分为数组id
      3. 在以&lt;/svg 开头的行上,遍历数组,将每个元素(行)打印到一个文件中,该文件通过将我们拆分的id[2] 的第二个结果与文件扩展名“.svg”连接起来命名。

      【讨论】:

        【解决方案4】:

        这是一个 consice awk 脚本来解决您的请求。 假设有一致的 6 行文件结构。

        script.awk

        {++line; lines = lines"\n"$0;}
        NR%6 == 2 {id = substr($3, 5, length($3)-5)".svg"; next;}
        NR%6 == 0 {
                print lines > id;
                line = 0; lines = "";
        }
        

        运行命令

        awk -f script.awk Original.svg
        

        如果您需要在 cmets 中的解释请求。

        【讨论】:

          猜你喜欢
          • 2021-01-27
          • 2022-11-01
          • 1970-01-01
          • 1970-01-01
          • 2018-06-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-04
          相关资源
          最近更新 更多