仅替换正则表达式匹配中的字符

时间:2014-01-10 17:49:21

标签: regex linux bash sed

我试图在textfile中搜索regex,而在匹配范围内只替换一个字符。我的问题是,我无法通过一些简单的方式来做到这一点。

示例源文件:

...
 <br>
<a id="some shopitem" ref="#some shop item name 01 a" style="text-decoration:none;"><h3 style="background-color: #ccc;">blah blab hasdk sldk sasdas dasda sd</h3></a>
<table>
 <td width="500">
....

我需要匹配regexp ref=\"#[[:alnum:] ]*\"(ref =“#任何带空格的名称”)并在匹配中用“ - ”替换空格,但当然不要更改另一个空格或正则表达式匹配。 / p>

所以结果应该是这样的:

....
 <br>
<a id="some shopitem" href="#some-shop-item-name-01-a" style="text-decoration:none;"><h3 style="background-color: #ccc;">blah blab hasdk sldk sasdas dasda sd</h3></a>
<table>
 <td width="500">
....

甚至可以在bash中的单行命令中没有某种脚本的情况下这样做吗?有没有办法如何替换组中的空格?类似于sed -r s/ref=\"#([[:alnum:] ]*\)/(\1s/ /-/g)/g'

2 个答案:

答案 0 :(得分:0)

perl解决方案:

perl -pe 's/(ref="#)([\w\s]+)(")/ ($x,$y,$z)=($1,$2,$3); $y =~ s{\s}{-}g; $x.$y.$z /eg'

对于可以出现在引用名称(下划线,制表符,其他一些空白字符)中的内容稍微宽容一点

答案 1 :(得分:0)

  

甚至可以在bash中的单行命令中没有某种脚本的情况下这样做吗?

你的问题在某种程度上引发了我这样做的野心......!

varfile=SOURCEFILE && varsubstfile=RESULTFILE && IFS=' ' read -a repl <<< $(sed -r 's/(.*)(ref="#.*?")( .*)/\2/;tx;d;:x' $varfile | sed -e 's/\ /\-/g' | sed ':a;N;$!ba;s/\s/ /g') && for i in "${!repl[@]}"; do needle["$i"]=$(sed 's/\-/\ /g' <<< "${repl["$i"]}"); done && cp $varfile $varsubstfile && for i in "${!needle[@]}"; do sed -ir "s/${needle[i]}/${repl[i]}/g" $varsubstfile; done && unset needle && unset repl && less $varsubstfile && unset varfile && unset varsubstfile

SOURCEFILE是您的源文件,RESULTFILE是输出写入的文件的名称,因此根据您的需要更改它们。

嗯......这是一个剧本,但它是一个(该死的巨大的)单行:)

我认为整个文件中出现ref="#.*"的次数更多,否则它会更短(虽然我不再记得更短的版本了)。

...我真的希望这适用于你的* nix系统:D

<小时/> 万一你想知道这件事是做什么的,这里有一个解释:

varfile=SOURCEFILE && #set variable for the sourcefile
varsubstfile=RESULTFILE && #set variable for the resultfile
IFS=' ' read -a repl <<< #we're going to read multiple values into an array "repl"
                         #delimited by a space
   $(
     #grab only the second capture group (ref="#.*?")
     sed -r 's/(.*)(ref="#.*?")( .*)/\2/;tx;d;:x' $varfile |
     sed -e 's/\ /\-/g' | #replace every space in (ref="#.*?") with a dash
     sed ':a;N;$!ba;s/\s/ /g' #replace newlines with a space
     #when there is more than one occurence sed will delimit them with a newline
     #but i set a space as the delimiter for the read operation,
     #thus the last replacement
   ) &&
#we now have every needed replacement-string in an array called "repl"
for i in "${!repl[@]}"; do #iterate over every value in the array we just read
  needle["$i"]=$(sed 's/\-/\ /g' <<< "${repl["$i"]}"); #replace dashes with spaces and store in a new variable
done &&
#and now every original string, the needle we are going to search for
#is stored in another array
cp $varfile $varsubstfile && #copy sourcefile to resultfile
for i in "${!needle[@]}"; do #for every string we are going to replace
  sed -ir "s/${needle[i]}/${repl[i]}/g" $varsubstfile; #... we replace it!
done
#technically we're done here
#but i like to clean up afterwards and show the result with less
unset repl && less $varsubstfile && unset varfile && unset varsubstfile