正则表达式:如何进行“选项拆分”替换

时间:2009-07-16 08:53:08

标签: php regex

那些令人反感的表达让我发疯。我坚持这个:

test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not

任务:
删除所有[[和]]如果有选项拆分选择后一个,那么输出应该是:

test1:link test2:silver test3:out1insideout2 test4:this|not

我提出了(PHP)

$text = preg_replace("/\\[\\[|\\]\\]/",'',$text); // remove [[ or ]]

这适用于任务的第1部分。但在此之前,我认为我应该选择拆分,我的最佳解决方案:

$text = preg_replace("/\\[\\[(.*\|)(.*?)\\]\\]/",'$2',$text);

结果:

test1:silver test3:[[out1[[inside]]out2]] this|not

我被困住了。也许有一些免费分钟的人可以帮助我?谢谢!

7 个答案:

答案 0 :(得分:1)

我认为最简单的方法就是多次通过。使用正则表达式,如:

\[\[(?:[^\[\]]*\|)?([^\[\]]+)\]\]

这将替换选项字符串,以便为您提供组中的最后一个选项。如果你重复运行直到它不再匹配,你应该得到正确的结果(第一遍将用[[out1insideout2]]替换[[out1 [[inside]] out2]],第二遍将抛弃括号。

编辑1 :作为解释,

\[\[        # Opening [[
(?:         # A non-matching group (we don't want this bit)
    [^\[\]] # Non-bracket characters
    *       # Zero or more of anything but [
    \|      # A literal '|' character representing the end of the discarded options
)?          # This group is optional: if there is only one option, it won't be present
(           # The group we're actually interested in ($1)
    [^\[\]] # All the non-bracket characters
    +       # Must be at least one
)           # End of $1
\]\]        # End of the grouping.

编辑2 :将表达式更改为忽略']'以及'['(它的效果更好)。

编辑3 :您无需知道嵌套括号的数量,因为您可以执行以下操作:

$oldtext = "";
$newtext = $text;
while ($newtext != $oldtext)
{
    $oldtext = $newtext;
    $newtext = preg_replace(regexp,replace,$oldtext);
}
$text = $newtext;

基本上,这会继续运行正则表达式replace,直到输出与输入相同。

请注意,我不懂PHP,因此上面可能存在语法错误。

答案 1 :(得分:0)

为什么要一次性完成所有操作。首先删除[[]],然后处理选项,用两行代码完成。

当试图获得有利于清晰和简单的东西时。

好像你有所有的作品。

答案 2 :(得分:0)

为什么不简单地删除任何剩下的括号?

$str = 'test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not';
$str = preg_replace('/\\[\\[(?:[^|\\]]+\\|)+([^\\]]+)\\]\\]/', '$1', $str);
$str = str_replace(array('[', ']'), '', $str);

答案 3 :(得分:0)

嗯,我并没有坚持只用正则表达式,因为我想要用一个大的正则表达式尝试做这样的事情会引导你进入一个关于“现在你有两个问题”的老笑话。但是,给这样的东西一个镜头:

$str = 'test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not'; $reg = '/(.*?):(.*?)( |$)/'; 
preg_match_all($reg, $str, $m);
foreach($m[2] as $pos => $match) {
  if (strpos($match, '|') !== FALSE && strpos($match, '[[') !== FALSE ) {
    $opt = explode('|', $match); $match = $opt[count($opt)-1]; 
  }
  $m[2][$pos] = str_replace(array('[', ']'),'', $match );
}

foreach($m[1] as $k=>$v) $result[$k] = $v.':'.$m[2][$k]; 

答案 4 :(得分:0)

由于您希望将内容保留在内容的多个“层次结构”中,因此无法在一个正则表达式中执行此操作。使用递归正则表达式成为可能。

无论如何,这是我能想到的最简单,最贪婪的正则表达式。如果内容符合您的确切要求,它应替换。

将字符串放入字符串时,您需要转义所有反斜杠(\变为\\。)

\[\[((?:[^][|]+|(?!\[\[|]])[^|])++\|?)*]]

正如其他人已经解释的那样,你可以使用多次传递。在有匹配项时保持循环,执行替换(仅保留匹配组1。)

与其他正则表达式的不同之处在于,它允许您在内容中使用单个括号,而不会破坏:

test1:[[link]] test2:[[gold|si[lv]er]]
test3:[[out1[[in[si]de]]out2]] test4:this|not

变为

test1:[[link]] test2:si[lv]er
test3:out1in[si]deout2 test4:this|not

答案 5 :(得分:0)

这是仅使用非转义字符串的C#,因此您必须将其他语言的反斜杠加倍。

String input = "test1:[[link]] " +
               "test2:[[gold|silver]] " +
               "test3:[[out1[[inside]]out2]] " +
               "test4:this|not";

String step1 = Regex.Replace(input, @"\[\[([^|]+)\|([^\]]+)\]\]", @"[[$2]]");
String step2 = Regex.Replace(step1, @"\[\[|\]\]", String.Empty);

// Prints "test1:silver test3:out1insideout2 test4:this|not"
Console.WriteLine(step2);

答案 6 :(得分:0)

$str = 'test1:[[link]] test2:[[gold|silver]] test3:[[out1[[inside]]out2]] test4:this|not';
$s = preg_split("/\s+/",$str);
foreach ($s as $k=>$v){
    $v = preg_replace("/\[\[|\]\]/","",$v);        
    $j = explode(":",$v);
    $j[1]=preg_replace("/.*\|/","",$j[1]);
    print implode(":",$j)."\n"; 
}