【问题标题】:Converting string but leave characters wrapped in braces转换字符串但将字符包裹在大括号中
【发布时间】:2018-10-17 17:43:33
【问题描述】:
  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);
}

返回abc_this_text

我想回ABC_this_text

【问题讨论】:

  • 在同一个字符串上使用 strtolower 两次可能与它有关....
  • @Andreas 那是个错误,代码已更新;)
  • 我会将工作分成两部分。一,检测大括号中的字符串,生成新的输出,然后,用[^a-zA-Z[]]+替换成_ ,我不懂很多php,就靠你了。

标签: php regex preg-replace preg-replace-callback


【解决方案1】:

您可以在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

第一个正则表达式详细信息:

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

第二个正则表达式:

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

【讨论】:

  • [] 不应该在那里
  • upvode .. 既然我知道你是htaccess之神,你能看看my question吗?
  • 谢谢,涵盖所有可能性。
【解决方案2】:

一种解决方案是将字符串拆分为单词数组。
如果单词包含 [] 仅删除它们,否则使用特殊字符和 strtolower 执行所有其他内容。

然后内爆回字符串并返回

$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

【讨论】:

  • 谢谢你的另一个好答案
【解决方案3】:

您可以使用 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,您可以使用字符类并添加您想要匹配的内容,例如[\w!?]+

Regex demo | Php demo

【讨论】:

  • 谢谢,这对我来说是最容易理解并且完美运行的。
【解决方案4】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-04
    • 2011-08-09
    • 2015-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-17
    相关资源
    最近更新 更多