skip to Main Content

Search in the array for the first occurrence of a string until space, then convert it to month.

$arr = [
 "May Hello",
 "Jun Hello12",
 "Jul 3"
];

$str =  $arr[0];
$matches = [];
$pattern = '/^w+s/';
preg_match_all($pattern, $str, $matches);

Replace $pattern in $arr:

$pattern = [
 '/^w+s/' => date('m', strtotime($matches[0][0])) . ' ', // fist string until space
];
$arr = preg_replace(array_keys($pattern), array_values($pattern), $arr);

echo '<pre>';
print_r($arr);
echo '</pre>';

unexpected:

Array
(
    [0] => 05 7 Hello
    [1] => 05 Hello12
    [3] => 05 3
)

expected:

Array
(
    [0] => 05 7 Hello
    [1] => 06 Hello12
    [3] => 07 3
)

What am I doing wrong?

3

Answers


  1. You should use preg_replace_callback when you want to run a function on the matched results:

    $arr = [
     "May Hello",
     "Jun Hello12",
     "Jul 3"
    ];
    
    $arr = preg_replace_callback(
            '/^(w+)s/',
            function ($matches) {
                return date('m', strtotime($matches[0])).' ';
            },
            $arr
        );
    
    echo '<pre>';
    print_r($arr);
    echo '</pre>';
    

    Output:

    Array
    (
        [0] => 05 Hello
        [1] => 06 Hello12
        [2] => 07 3
    )
    
    Login or Signup to reply.
  2. Use a word boundary in the pattern to ensure that only a 3-letter word is found at the start of the string. In the closure, you can convert the fullstring match to its zero-padded month number and omit the concatenation of a trailing space.

    Code: (Demo)

    var_export(
        preg_replace_callback('/^[A-Z][a-z]{2}b/', fn($m) => date('m', strtotime($m[0])), $arr)
    );
    

    For better processing economy, you can keep a cache of translated month values to avoid calling two functions (or instantiating a datetime object and calling a method) to generate replacement strings each time. The closure becomes a little more verbose though. (Demo)

    var_export(
        preg_replace_callback(
            '/^[A-Z][a-z]{2}b/',
            function($m) {
                static $trans = [];
                $trans[$m[0]] ??= date('m', strtotime($m[0])); // only assign / call functions if needed
                return $trans[$m[0]];
            },
            $arr
        )
    );
    

    Depending on your input strings, if the letters of the 3-letter month are guaranteed to not occur later in the string then you can create a translation array and call strtr() to avoid regex. (Demo)

    $trans = [
        'Jan' => '01',
        'Feb' => '02',
        'Mar' => '03',
        'Apr' => '04',
        'May' => '05',
        'Jun' => '06',
        'Jul' => '07',
        'Aug' => '08',
        'Sep' => '09',
        'Oct' => '10',
        'Nov' => '11',
        'Dec' => '12'
    ];
    
    foreach ($arr as $v) {
        echo strtr($v, $trans) . "n";
    }
    
    Login or Signup to reply.
  3.     $len = count($arr);
    
        for ($i=0; $i<$len; $i++) {
            $element = $arr[$i];
            $letterMonth = substr($element, 0, 3);
            $dateObj = DateTime::createFromFormat('F', $letterMonth);
            $month = $dateObj->format('m');
            $arr[$i] = str_replace($letterMonth, $month, $element );
        }
    
        return $arr;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search