Cem Firat
Cem Firat

Reputation: 410

Replace 3-letter month with its month number in an array of strings

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?

Upvotes: 0

Views: 244

Answers (3)

mickmackusa
mickmackusa

Reputation: 47904

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";
}

Upvotes: 2

usrobotics
usrobotics

Reputation: 64

    $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;

Upvotes: 0

cOle2
cOle2

Reputation: 4784

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
)

Upvotes: 2

Related Questions