文件中的字符串替换

文件中的字符串替换

我有以下文件:

<?xml version="1.0" encoding="utf-8"?>
<!--Generated by crowdin.net-->
  <string name="test" >- test</string>
  <string name="test" >test-test</string>
  <string name="test" >test - test</string>

我想en dash用它的 unicode 值替换 ,但不是全部,只是string标记中的一个

我用不同的正则表达式运行了几个sed,但我无法弄清楚。其中之一是

sed -i.bak "s/-[^-\<\>0-9]/\&#8211\;/g" strings.xml

输出是:

<?xml version="1.0" encoding="utf-8"?>
<!-&#8211;enerated by-->
  <string name="test" >&#8211;test</string>
  <string name="test2" >test&#8211;est</string>
  <string name="test3" >test &#8211;test</string>

我的问题是也在更换空白处第一个字符第二个词的。我对regex和没有那么丰富的经验sed。你能解释一下我做错了什么吗?

注意:我使用的是 OSX。

答案1

使用最近的( for\Ks///rperl并假设您的<string>标签不嵌套:

perl -0777 -pi.bak -e's{<string.*?>\K.*?(?=</string>)}{$&=~s/-/&#8211;/rg}ges' file.xml
  • -0777:吸食模式:一次处理整个文件(以允许<string>标签跨越多行)。
  • -psed模式
  • -i.bak:带有扩展的就地编辑.bak(顺便说一句,这就是一些sed实现的想法来源)
  • s{...}{...}ges:全局替换 ( g),其中.也匹配换行符 ( s),并将替换视为perl要执行的代码 ( e)。
  • <string.*?>\K.*?</string>: 匹配 from <string...>to</string>但不将标签本身包含在 is 的部分中匹配的(\K定义了其中匹配的部分开始,并且(?=...)是一个前瞻运算符,仅检查if</string>存在,但不将其包含在匹配中)。
  • $&=~s/.../.../rg。进行替换匹配的部分 ($&)。该r标志实际上不修改$&而是返回替换的字符串。

答案2

唷,过了一段时间我就明白了。这是一个幼稚的解决方案。特登的回答更正确,你应该使用他的:)。

sed -Ei.bak "s/(.*<string[^>]*\")(.*)-(.*)/\1\2\&#8211;\3/g" strings.xml

我在用反向引用引用先前匹配的字符串。这些都是\1 \2等等

在这种情况下 sed 应匹配以下组:

  • (.*<string[^>]*\")- 任何字符后跟一个字符串标记,直到引号为止"第 1 组
  • (.*)- 之后"(包括现在>)直到第 3 组的任何内容。第2组
  • -匹配的破折号
  • (.*)- 匹配破折号后的任何内容第3组

然后,我将其替换为之前匹配的组和破折号 HTML 值&#8211;,并使用\nwithn作为对组的引用n

问题:

我目前正在尝试解决一些问题,所以请配合我:

  1. 第 1 组比赛也dsfjpasj<string
  2. 第 1 组应包含字符串标记结束字符>
  3. >1 -正如 terdon 指出的那样:“这对于拥有或嵌套标签或跨越多行的标签的情况不起作用”

阅读更多:

http://toytoygogie.blogspot.de/2010/02/using-sed-with-backreference-as.html

答案3

如果我理解正确,您想要替换标记-内的所有情况(示例中为三个)<strng></string>并且仅替换这些情况。如果是这样,这些方法应该有效假设你的 XML 是正常的:

  1. 使用正则表达式和简单的工具,例如sed

    sed 's/\(<string[^>]*>[^-]*\)-\([^-]*<\/string\)/\1\&#8211;\2/' file.xml 
    
  2. 如果你的文件是总是就像上面的例子,你可以确定你的标签将永远是<string name="test" ></string>,你可以使用回顾:

    perl -pe 's/(?<=<string name="test" >)([^<]*?)-([^<]*)/$1&#8211;$2/g' file.xml
    
  3. -如果标签内有多个标签,则以上方法都不起作用。为了处理这种情况,您可以编写一个简单的小脚本来检查我们是否在<string></string>标签内。这也应该处理嵌套标签。

    perl -F'<' -lane 'for($i=0;$i<=$#F;$i++){
        $a++ if $F[$i]=~/^string/; 
        $F[$i]=~s/-/&#8211;/g if $a>0; 
        $a-- if $F[$i]=~/^\/string/
    } print join "<",@F' file.xml
    

相关内容