Простая инкрементная замена строки в php - PullRequest
0 голосов
/ 07 сентября 2011

У меня есть следующий код:

<?php
$subject = "Replace ? question mark in brackets [? with ? incremental ??]? digits";
echo incremental_replace($subject);
// i want the folowing: 
// Replace ? question mark in brackets [1 with 2 incremental 34]? digits

Я хочу заменить все ? в скобках. Кроме того, число и позиция ? могут измениться.

Как мне это сделать с php? Я думаю, что это можно сделать с помощью preg_replace, но я не знаю как.

Ответы [ 5 ]

3 голосов
/ 07 сентября 2011

если скобки не являются вложенными, то следующего будет достаточно

echo preg_replace('~\?(?=[^\[\]]*\])~e', '++$n', $subject);

в противном случае используйте парсер:

$subject = "Replace ? question mark in [nested ? brackets] [? with ? [incremental ? [?]] ??]? digits";
$result = '';

$bc = $n = 0;
foreach(str_split($subject) as $c) {
    if($c == '[') $bc++;
    if($c == ']') $bc--;
    if($c == '?' && $bc) $c = ++$n;
    $result .= $c;
}

echo $result;

Возможно регулярное выражение для вложенных скобок, но оно будет слишком длинным и запутанным.


Примечание по OP : Если замены не инкрементные цифры, а массив, вы можете сделать следующее:

$n = 0;
$rep = array('foo', 'bar', 'baz', 'qux', 'quux');
echo preg_replace('~\?(?=[^\[\]]*\])~e', '$rep[$n++]', $subject);
2 голосов
/ 07 сентября 2011

Правильное решение проблемы

function incremental_replace($subject) {
    $replacer = function($matches) {
        $index = 0;
        return preg_replace('/\?/e', '++$index', $matches[0]);
    };
    return preg_replace_callback('/\[[^\]]*\]/', $replacer, $subject);
}

$subject = "Replace ? question mark in brackets [? with ? incre?mental ??]?...";
echo incremental_replace($subject);

Предыдущая форма этого ответа

Я неправильно понял вопрос и вместо этого ответил на другой похожий вопрос. Я оставляю ответ здесь, потому что кто-то может найти его полезным.

Общая идея такова:

function replacer($matches) {
    $replacements = array(1, 2, 34);
    $index = 0;
    return preg_replace('/\?+/e', '$replacements[$index++]', $matches[0]);
}

$subject = "Replace ? question mark in brackets [? with ? incremental ??]?...";
echo preg_replace_callback('/\[[^\]]*\]/', 'replacer', $subject);

См. Базовую концепцию в действии .

Если вы используете PHP> = 5.3, вы можете сделать гораздо более обобщенное решение:

function incremental_replace($subject, $replacements) {
    $replacer = function($matches) use ($replacements) {
        $index = 0;
        return preg_replace('/\?+/e', '$replacements[$index++]', $matches[0]);
    };
    return preg_replace_callback('/\[[^\]]*\]/', $replacer, $subject);
}


$subject = "Replace ? question mark in brackets [? with ? incremental ??]?...";
echo incremental_replace($subject, array(1, 2, 34));

Наконец, если вы хотите ограничить себя только одним знаком вопроса (т. Е. Если ?? внутри скобок можно изменить просто на ?), тогда вы можете поменять preg_replace внутри функции «replacer» с простым str_replace, который был бы быстрее.

1 голос
/ 07 сентября 2011
function replaceThem($matches){
    $i = 1;
    while ($pos = strpos($matches[0], '?'))
        $matches[0][$pos] = $i++;
    return $matches[0];
}
$subject = "Replace ? question mark in brackets [? with ? incremental ??]? digits";
echo preg_replace_callback('/\[[^\]]+\]/', 'replaceThem', $subject);

http://www.ideone.com/kBnMK

1 голос
/ 07 сентября 2011

Простой парсер может сделать эту работу.Это просто простое решение с возможностью улучшения.Но, возможно, preg_replace() или preg_replace_callback() могут быть более эффективными в этом случае.

function incremental_replace($subject) {
    $inBracket  = 0;
    $length = strlen($subject);
    $count      = 0;
    $result = '';
    for ($i = 0; $i < $length; $i++) {
        $char = $subject[$i];
        switch ($char) {
            case '[':
                $inBracket++;
                break;
            case ']':
                $inBracket--;
                break;
            case '?':
                if ($inBracket > 0) {
                    $char = ++$count;
                }
                break;
        }
        $result .= $char;
    }
    return $result;
}

$subject = "Replace ? question mark in brackets [? with ? incremental ??]? digits";
echo incremental_replace($subject);
// Replace ? question mark in brackets [1 with 2 incremental 34]? digits
0 голосов
/ 07 сентября 2011

Возможно, лучше перебрать символы строки.Если вы пройдете через открывающую скобку, замените вопросительные знаки, с которыми вы сталкиваетесь, на счетчик, то же самое для второй и т. Д., А если вы пройдете через закрывающую скобку ... прекратите замену.

...