仅移除数组键的开头潜在字符

3

使用 PHP...

我有一个数组(虽然是多维的,但我只关心此情况下的顶层),其中键是字符串,具有各种形式。示例键包括:

  • Fred Smith
  • Dr John Paul
  • Dr. Mary Ellen
  • Bill Driver

我需要一个函数来从任何发现它们的键的开头仅删除 'Dr'、'Dr '、'Dr'、'Dr. '。我目前正在使用以下代码:

function fixArrayKey(&$arr) {
$arr = array_combine(
    array_map(
        function ($str) {
            return str_replace(array('Dr. ', 'Dr.', 'Dr ', 'Dr'), '', $str);
        },
        array_keys($arr)
    ),
    array_values($arr)
);

我在这里找到了一个答案How to remove spaces in array keys names in php?

它几乎帮助我完成了任务,但是它将会匹配字符串中的任何位置,所以最终我得到了以下结果:

  • Fred Smith
  • John Paul
  • Mary Ellen
  • Bill iver

我感觉需要使用 preg_replace(),类似于这个例子Remove a string from the beginning of a string,我认为我可以在 preg_replace() 中设置限制,但我不确定。我也看过 ltrim(),但它并不完全正确。我的问题是可能找不到匹配项,或者匹配项可能长达2、3或4个字符,并且在字符串中间可能存在我不想删除的匹配项。

我是否正在正确地查找 preg_replace()?


尝试使用 preg_replace('~^Dr\.?\s*~', '', $str) - Wiktor Stribiżew
转念一想,preg_replace('~^Dr\b\.?\s*~', '', $str) 应该更好。 - Wiktor Stribiżew
我添加了一个带有解释的答案。 - Wiktor Stribiżew
AbraCadaver,不行。我正在使用@Wiktor Stribiżew下面的正则表达式,并在其中使用单词边界标记。它可以捕获边缘情况“Dr.Mary Cross”,其中前缀和名字之间没有空格。我想尝试将其纳入您的一行代码中,但第一次失败了,我还没有机会回来处理它。谢谢大家。 - verdonv
3个回答

2
你应该能够使用这个正则表达式涵盖所有情况。只需要更改return部分即可:
return preg_replace('/^Dr\.?\s+/', '', $str);
  • ^表示替换字符串的开头,用Dr替换。
  • 可以选择性地在?后面替换.
  • 替换1个或多个空格\s+后面

然而,为了消除当前所有代码,您可以使用:

$array = array_combine(preg_replace('/^Dr\.?\s+/', '', array_keys($array)), $array);

使用第二个 ? 会导致匹配像 Draco、Drake、Dreyfus 等名字的首字母。我建议将其替换为 +,表示 一个或多个 空格,而不是 * - Ben.12
好的,我会这样做。一开始我只是按照原帖的内容进行操作。 - AbraCadaver
我无法让这个一行代码正常工作,但我会琢磨出来的。使用 preg_replace 的返回值确实有效,但你在其中多了一个圆括号。应该是 preg_replace('/^Dr.?\s+/', '', $str);。 - verdonv
抱歉,我在两个地方都放错了 )。我已经编辑过了,应该可以正常工作了。 - AbraCadaver

1

你是正确的,preg_replace 对于你来说将起作用,因为你可以使用锚点和单词边界轻松地删除 整个单词

使用

return preg_replace('~^Dr\b\.?\s*~', '', $str);

查看正则表达式演示。注意,我添加了Draco Malfoy作为额外的测试字符串。 正则表达式在这里不会删除Dr。原因见下文。

详细信息

  • ^ - 字符串开头
  • Dr\b - 整个单词Dr(因为\b是一个单词边界)
  • \.? - 一个或零个点
  • \s* - 一个或多个空格。

我喜欢单词边界标记。我之前不知道这个。这个表达式也可以用,就像上面那个一样。 - verdonv
但是使用Draco Malfoy进行测试,你会感受到不同。我认为所有其他解决方案都没有检查只匹配整个单词的情况。 - Wiktor Stribiżew
我用@AbraCadaver提供的正则表达式'/^Dr.?\s+/'进行了测试,即使是Draco Malfoy也可以匹配成功,正则表达式太优美了 :-) - verdonv
正则表达式有问题,在结尾处有 \s*。因此,如果没有空格,它就无法工作。例如:Dr.Mary Cross。虽然由您来选择接受的答案,但我仍然认为正确的方法是使用单词边界。 - Wiktor Stribiżew
很好的发现和观点.. 顺便说一下... 真喜欢 regex101 网站! - verdonv

0
$names = array(
    'Fred Smith' => true,
    'Dr John Paul' => true,
    'Dr. Mary Ellen' => true,
    'Bill Driver' => true,
);

foreach($names as $key => $val) {
  $temp_key = strtolower(trim(substr($key, 0, 2)));
  if($temp_key == "dr") {
       unset($names[$key]);
       $names[trim(substr($key, 3))] = $val;
  }
}

print_r($names);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接