转换字符串但将字符用大括号括起来

Converting string but leave characters wrapped in braces

  1. 我正在转换用户输入的字符串(成功但是...)
  2. 我想忽略用大括号包裹的字符
  3. 也去掉最终输出中的大括号

例如,如果我有这个字符串:

$string = "[ABC] This & Text";

function make_post_type($string) {
  $needle   = array('-', ' ');
  $clean    = preg_replace("/[^a-zA-Z0-9_\s]/", "", strtolower($string)); // Remove special characters
  $haystack = preg_replace('!\s+!', ' ', $clean); // Now remove extra spaces

  return str_replace($needle, '_', $haystack);
}

returns abc_this_text

我愿意returnABC_this_text

一种解决方案是将字符串拆分为单词数组。
如果这个词包含 [] 只删除它们,否则用特殊字符和 strtolower 做所有其他的事情。

然后内爆回到字符串 return

$string = "[ABC] This & Text";
Echo make_post_type($string);


function make_post_type($string) {
  $needle   = array('-', ' ');
  $arr = explode(" ", $string);
  foreach($arr as &$a){
     if($a[0] != "[" && $a[-1] != "]"){
        $a = preg_replace("/[^a-zA-Z0-9_\s]/", "", strtolower($a)); // Remove special characters
     }else{
        $a = substr($a, 1,-1);
     }
  }
  $string = preg_replace('!\s+!', ' ', implode(" ", $arr)); // Now remove extra spaces

  return str_replace($needle, '_', $string);
}

https://3v4l.org/rZlaP

您可以在 preg_replace_callback:

中使用此正则表达式代码
function replc($str) {
   return preg_replace_callback (
      '/\[([^]]*)\]|{([^}]*)}|([^][{}]+)/',
      function ($m) {
         return (isset($m[1])?$m[1]:"") .
                (isset($m[2])?$m[2]:"") .
                 (isset($m[3]) ?
                 preg_replace('/\W+/', '_', strtolower($m[3])) : "");
      },
      $str
   );
}

称其为:

echo replc( "[ABC] This & Text" );
ABC_this_text

echo replc( "abc.Xyz {PQR} Foo-Bar [ABC] This & Text" );
abc_xyz_PQR_foo_bar_ABC_this_text

第一个 RegEx 详细信息:

  • [([^]]*)\]:如果我们遇到[...],则在组#1
  • 中捕获内部部分
  • |: 或
  • {([^}]*)}:如果我们遇到{...},那么在组#2
  • 中捕获内部部分
  • |: 或
  • [^][{}]+:匹配 1+ 个不是 []{} 的字符并捕获到组 #3

第二个正则表达式:

  • \W+:匹配1+个非单词字符被_
  • 替换

您可以使用 preg_match_all 并使用 2 个捕获组。

\[([A-Z]+)\]|(\w+)

使用 array_reduce 按索引检查捕获组,最后使用下划线内爆:

例如:

$re = '/\[([A-Z]+)\]|(\w+)/';
$string = "[ABC] This & Text";
preg_match_all($re, $string, $matches, PREG_SET_ORDER, 0);

echo implode('_', array_reduce($matches, function($carry, $item){
    if ($item[1] === "") {
        $carry[] = strtolower($item[2]);
        return $carry;
    }
    $carry[] = $item[1];
    return $carry;

})); //ABC_this_text

说明

  • \[([A-Z]+)\] 匹配[,捕获一组中的1+个大写字符并匹配]。要匹配括号之间的所有内容,您可以改用 \[([^]]+)\]
  • |
  • (\w+) 抓取一组1+字字符。如果你想匹配超过 \w 你可以使用字符 class 并添加你想要匹配的内容,例如 [\w!?]+

Regex demo | Php demo

您可以通过以另一种方式查看问题来减少生成所需字符串的步骤。首先匹配您需要的内容,然后在末尾用 _ 替换空格和破折号:

function make_post_type($s) {
    preg_match_all("~({[^{}]*}|\[[^][]*])|[\w\s]+~", $s, $m);
    $s = '';
    foreach($m[0] as $k => $v) {
        $s .= $m[1][$k] ? substr($v, 1, -1) : strtolower($v);
    }
    return preg_replace('~[-\s]+~', '_', $s);
}

我将 {[^{}]*}|\[[^][]*] 括在括号中,以便稍后检查 (bool) $m[1][$k],它告诉 $m[1] 返回的捕获组中是否存在迭代中的当前值,然后去掉一个前导和字符串的尾随字符。

live demo here