Как удалить / заменить определенные символы как из ключей, так и из значений в массиве?

Моя цель - удалить группу символов из ключей одномерного массива и другую группу символов из значений этого же массива. Пример:

$arr = [
  'a' => 'Letter A!',
  '`b`' => 'Letter B w/quotes...',
  ' c ' => 'Letter C w/spaces?',
  ' -_-`d`- _ - ' => 'Letter D w/all?!...'
];
$invalid_keys_chars = ['`',' ','_','-'];
$invalid_vals_chars = ['!','?','.'];

// GOAL: looking for something like this function
array_del_invalid($arr, $invalid_keys_chars, $invalid_vals_chars));
var_export($arr);
// ---> output
// array (
//   'a' => 'Letter A',
//   'b' => 'Letter B w/quotes',
//   'c' => 'Letter C w/spaces',
//   'd' => 'Letter D w/all'
// )

Сначала я посмотрел на общие функции PHP:

  • array_walk пример: допускает замену значений по ссылке, но если я также передам ключ по ссылке в параметрах обратного вызова, то этого не произойдет;
  • array_replace: ключи также не изменены;
  • array_map пример: создание копии массива, но предыдущая обработка array_keys($arr) является необходимым.

Поэтому моя цель - выполнить все замены за один раз, избегая повторного использования функций PHP, которые зацикливаются несколько раз в массиве.

Я разместил ответ в этой же теме с моей попыткой, которая работает, но я не мог найти способ избежать unset($arr[$invalid_key]) (есть ли другой способ "изменить" сам ключ, не удаляя его?) или выполнить только одно присваивание, если строки ключа и значения нуждаются в замене.

Есть ли уже функция PHP, которая делает это? Т.е. однопетлевое, мало условий, минимум замен и в целом более эффективно? Если нет, как я могу улучшить мой?

2 ответа

Решение

Нет, в PHP нет способа изменить ключ массива по ссылке. Вы можете только добавлять и удалять ключи.

Четное array_change_key_case создаст новый массив вместо изменения оригинала.

Вы можете создать новый массив в своей функции и вернуть новый массив. Затем вы можете перезаписать исходную переменную массива чистой версией.

<?php
function deleteInvalid($dirty, $ikc = [], $ivc = []) {
    $clean = [];
    foreach ($dirty as $key => $val) {
        $cKey = str_replace($ikc, '', $key);
        $cVal = str_replace($ivc, '', $val);
        $clean[$cKey] = $cVal;
    }
    return $clean;
}

$dirty = deleteInvalid($dirty);
var_dump($dirty);

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

<?php
if (is_string($val)) {
    // do something with the string.
}

Без использования функций библиотеки массивов:

function array_del_invalid(&$a, $ikc = [], $ivc = []) {
  if(! empty($ikc) || ! empty($ivc)) {
    foreach ($a as $k => $v) {
      $treated_key = str_replace($ikc, '', $k);
      $treated_val = str_replace($ivc, '', $v);
      if($k !== $treated_key) {
        unset($a[$k]);
        $a[$treated_key] = $v;
      }
      if($v !== $treated_val) {
        $a[$treated_key] = $treated_val;
      }
    }
  }
}
$arr = [
  'a' => 'Letter A!',
  '`b`' => 'Letter B w/quotes...',
  ' c ' => 'Letter C w/spaces?',
  ' -_-`d`- _ - ' => 'Letter D w/all?!...'
];
$original_arr = $arr;
$invalid_keys_chars = ['`',' ','_','-'];
$invalid_vals_chars = ['!','?','.'];
array_del_invalid($arr, $invalid_keys_chars, $invalid_vals_chars);
var_export($arr);
// ---> output
// array (
//   'a' => 'Letter A',
//   'b' => 'Letter B w/quotes',
//   'c' => 'Letter C w/spaces',
//   'd' => 'Letter D w/all'
// )

// only keys replacement
$arr = $original_arr;
array_del_invalid($arr, $invalid_keys_chars);
var_export($arr);
// array (
//   'a' => 'Letter A!',
//   'b' => 'Letter B w/quotes...',
//   'c' => 'Letter C w/spaces?',
//   'd' => 'Letter D w/all?!...',
// )

Работает онлайн @ array_del_invalid на 3v4l.org.

Другие вопросы по тегам