2013-11-15 75 views
0

我想這樣做

在PHP中,這樣的事情:如何使用默認值在php preg_replace函數中沒有匹配的引用?

$input = '23:10'; 
$pattern = '/^(\d?\d):(\d?\d)(:(\d?\d))?$/'; 
$rewrite = '$1h$2m$4s'; 

$output = preg_replace($pattern, $rewrite, $input); 
echo $output; 

$input可以帶或不帶秒的時間,但沒有秒,它應該返回「0」爲默認$4在替換字符串中。所以輸出,也就是現在:

23h10ms 

應該是:

23h10m0s 

重要:

對於解決它的真正重要的是最後一個函數的輸入由任意$pattern的和$rewrite字符串,將$input字符串轉換爲輸出格式。因此,對於該秒部分沒有硬編碼檢查,但是在$rewrite字符串中插入參考的默認值的一般方法是參考$pattern字符串中的可選部分。該函數也應用於與(例如)的情況下工作:

$input = '3 hours'; 
$pattern = '/^(\d+) hours(and (\d+) minutes)?(and (\d+) seconds)?$/'; 
$rewrite = '$1h$3m$5s'; 

作爲該實施例說明,我有超過所需的格式($pattern + $rewrite)沒有控制,所以他們可以改變相當多。最重要的原因是:輸入和輸出也可能會用其他語言編寫,因此$pattern$rewrite從語言文件(Joomla)中獲得。

來解決

可能的方向,到目前爲止我來最接近的是以下幾點:

這個
// Get a $matches array: 
preg_match($pattern, $input, $matches); 

// Replace the references ($1, $2, etc.) in the rewrite string by these matches: 
$output = preg_replace_callback(
    '/\$(\d+)/g', 
    function($m) { 
    $i = $m[1]; 
    return (isset($matches[$i]) ? $matches[$i] : '0'); 
    }, 
    $rewrite 
); 

兩件事情:1。 它尚不能工作,因爲$匹配不可用在回調函數中。 2.使用重寫字符串作爲preg_replace_callback()的輸入變得非常棘手。

回答

0

更新

對於有用的功能是動態的,我建議你寫一個新的類,其中所有需要的信息都是屬性。在該課程內部,您可以使用成員方法調用preg_replace_callback,並檢查是否存在所有需要的組 - 如果不存在,則應使用定義的$defaultValue替換它。

class ReplaceWithDefault { 

    private $pattern, $replacement, $subject, $defaultValue; 

    public function __construct($pattern, $replacement, $subject, $defaultValue) { 
     $this->pattern = $pattern; 
     $this->replacement = $replacement; 
     $this->subject = $subject; 
     $this->defaultValue = $defaultValue; 
    } 

    public function replace() { 
     return preg_replace_callback($this->pattern, 'self::callbackReplace', $this->subject); 
     //alternative: return preg_replace_callback($this->pattern, array($this, 'callbackReplace'), $this->subject); 
    } 

    private function callbackReplace($match) { 
     // fill not found groups with defaultValue 
     if (preg_match_all('/\$\d{1,}/i', $this->replacement, $values)) { 
      foreach ($values[0] as $value) { 
       $index = substr($value, 1);//get rid of $ sign 
       if (!array_key_exists($index, $match)) { 
        $match[$index] = $this->defaultValue; 
       } 
      } 
     } 

     $result = $this->replacement; 
     // do the actual replacement 
     krsort($match); 
     foreach ($match as $key=>$value) { 
      $result = str_replace('$'.$key, $value, $result); 
     } 
     return $result; 
    } 

} 

您將需要krsort(),所以它不會錯誤,例如, $15{$1}5

類,現在可以像這樣使用

$originalQuestion = new ReplaceWithDefault('/^(\d?\d):(\d?\d)(:(\d?\d))?$/', 
    '$1h$2m$4s', 
    '23:10', 
    '00'); 
$updatedQuestion = new ReplaceWithDefault('/^(\d+) hours(and (\d+) minutes)?(and (\d+) seconds)?$/', 
    '$1h$3m$5s', 
    '3 hours', 
    '0'); 

print "<pre>"; 
var_dump($originalQuestion->replace()); 
var_dump($updatedQuestion->replace()); 

而且會產生想要的結果。


原帖

我不知道這是否可以用常規preg_replace()來完成。但是,PHP提供了另一種可能性:preg_replace_callback()。定義函數時,可以使用更復雜的邏輯。

$input = '23:10'; 
$pattern = '/^(\d?\d):(\d?\d)(:(\d?\d))?$/'; 

function correctFormat($hit) { 

    if (isSet($hit[4])) 
     $seconds = $hit[4]; 
    else 
     $seconds = "0"; 

    return $hit[1]."h".$hit[2]."m".$seconds."s"; 
} 

$output = preg_replace_callback($pattern, "correctFormat" , $input); 
echo $output; 

我提出一個解決方案,通過Chinnu R所示,由於正則表達式顯然是沒有必要的,也沒有優勢,常規爆炸在這種情況下。

+0

感謝您的回答。但是,這正是我在問題的最後一段試圖避免的那種答案。我在這裏簡化了案例以說明它,但實際情況是我得到了一個模式和一個重寫(然後比我的例子複雜得多),我必須編寫一個函數來使用它們來轉換輸入值。因此,使用重寫字符串而不是像'return'後面那樣對格式進行硬編碼。 – Herman

+0

順便說一句。變量名稱'$ hit'的不錯選擇。一旦你看到美元符號爲's',你就無法正常閱讀:) – Herman

+0

當我命名'$ hit'時,我確實沒有這樣想過^^''你也可以動態地返回這裏,它是隻是更復雜一點。假設你的'$ rewrite'字符串是固定的,你需要一個替換$ 1 => $ hit [1],$ 2 => $ hit [2]'等的函數,並且可以使用給定的字符串。但要以一種優雅的方式做到這一點將會很複雜,我建議使用一個單獨的課程。請更新您的示例,以便它適合您的需求並在此問題上進行教育 - 這樣的代碼片段寫起來很快,但我們不會使用複雜的邏輯編寫單獨的preg_replace方法。 – kero

-1

希望這可以幫助你,

$input = '23:10';  
    list($h, $m,$s) = explode(":", date('H:i:s', strtotime($input)));  
    echo $h."h".$m."m".$s."s"; 

另一種方法;

$input = '23:10'; 
    list($h, $m, $s) = explode(":", $input);  
    if($s==""){ $s="00";}; 
    echo $h."h".$m."m".$s."s"; 
+0

感謝您的回答。但是,這正是我在問題的最後一段試圖避免的那種答案。我在這裏簡化了案例來說明它,但實際情況是我得到了一個模式和一個重寫(然後我的示例更復雜),我必須編寫使用它們來轉換輸入值的函數。但對於不匹配的引用,默認值爲'0'。 – Herman