regex 通过删除字符串中间的分隔字将段塞截断到最大长度

knpiaxh1  于 2023-05-30  发布在  其他
关注(0)|答案(3)|浏览(121)

我正试图确保一个slug格式的字符串是在总字符的限制,从中间删除的字符串,如果保证。
样品段塞:
'/job/hello-this-is-my-job-posting-for-a-daycare-im-looking-for-in-91770-rosemead-california-12345'
字符串将始终以/job/开始,以in-zipcode-city-state-job_id结束。然而,有一个150个字符的限制,以蛞蝓和我期待截断前的话邮编一次,所以这个字符的限制是不超过。我知道我必须使用regex/explode,但我如何才能做到这一点?我尝试了下面的方法,但是我的matches数组似乎有太多的元素。

$pattern = '/-in-\d{5}-(.*)-(.*)-(\d*)/';
$string = '/job/hello-this-is-my-job-posting-for-a-daycare-im-looking-for-in-91770-rosemead-california-12345';

preg_match($pattern, $string, $matches);
print_r($matches);

// Array
(
    [0] => -in-91770-rosemead-california-12345
    [1] => rosemead
    [2] => california
    [3] => 12345
)

为什么rosemeadcalifornia12345被认为匹配?不是应该只有第一个元素吗?
如何确保完整的slug最大长度为150个字符,并完整地包含尾随部分(位置),如果需要,则截断前导部分(作业名称)?

esyap4oy

esyap4oy1#

您可以在不使用explode()和迭代的情况下做到这一点,只需使用一些标准的字符串操作:

$pattern = '/-in-\d{5}-.*-.*-\d*/';
$string = '/job/hello-this-is-my-job-posting-for-a-daycare-im-looking-for-in-91770-rosemead-california-12345';
$matches = [];

if (!preg_match($pattern, $string, $matches)) {
    // mismatched string - error handling here
}

$totalLength = 150;
$maxPrefixLength = $totalLength - strlen($matches[0]);
if ($maxPrefixLength < strlen('/job/')) {
    // no prefix words possible at all - error handling here
}
$prefixLength = max(strlen('/job/'), strrpos(substr($string, 0, $maxPrefixLength), '-'));
$slug = substr($string, 0, $prefixLength) . $matches[0];
ig9co6j1

ig9co6j12#

将URL slug的前导部分修剪为指定长度可以通过多种方式来完成,其中一些方式比其他方式更复杂。这里有一个灵活的实用函数,带有信息性注解。我们使用一个正则表达式,它提取开头部分(作业名称)和结尾部分(位置)作为起点。然后,根据允许的总长度减去位置段塞长度,计算作业名称的最大允许长度。查看评论了解更多信息。

function trim_slug(string $slug, int $maxlen = 150): string
{
    // check if trimming is required:
    if(strlen($slug) <= $maxlen) {
        return $slug; 
    }
    
    $pattern = '/^(?<job>.+)(?<loc>-in-\d{5}-.*-.*-\d*)$/';
    // $match will have 'job' and 'loc' named keys with the matched values
    preg_match($pattern, $slug, $match);
    
    // raw cut of job name to maximum length:
    $max_job_chars = $maxlen - strlen($match['loc']);
    $job_name = substr($match['job'], 0, $max_job_chars);
    
    // tidy up to last delimiter, if exists, instead of mincing words:
    if($last_delim = strrpos($job_name, '-')) {
        $job_name = substr($match['job'], 0, $last_delim);      
    }
    
    return $job_name . $match['loc'];
}

$string = '/job/hello-this-is-my-job-posting-for-a-daycare-im-looking-for-in-91770-rosemead-california-12345';

echo trim_slug($string, 80);
// result: /job/hello-this-is-my-job-posting-for-a-in-91770-rosemead-california-12345

在用法示例中,最大长度为80,因为示例字符串只有97个字符,因此将从函数返回默认的150个字符限制。Demo at 3v4l
请注意,这个答案使用了PHP标准的字符串函数,这些函数不支持多字节。如果需要多字节内容,则应使用相应的multibyte string functions以避免数据损坏。(你是否希望URL slug中的多字节字符开始,以及处理它的最佳方法是什么,是另一个问题的主题。

qltillow

qltillow3#

1.把输入的子弹分解成三个关键部分,
1.通过从总允许量中减去第一和第三长度来计算中间部分允许的字符数,
1.通过在达到字符限制之前找到最后出现的连字符来截断中间部分(干净地),然后删除剩余的可消耗子串。
这将为您提供一个优化的字符串,以获得最大长度,而不会损坏slug中的整个单词。
代码:(Demo

$slug = '/job/hello-this-is-my-job-posting-for-a-daycare-im-looking-for-in-91770-rosemead-california-12345';

$slugLimit = 70;

echo preg_replace_callback(
         '~^(/job/)((?:[^-]*-)*)(in-\d{5}-[^-]*-[^-]*-\d*)$~u',
         fn($m) => implode([
             $m[1],
             preg_replace(
                 '~^.{0,' . ($slugLimit - mb_strlen($m[1] . $m[3]) - 1) . '}-\K.*~u',
                 '',
                 $m[2]
             ),
             $m[3]
         ]),
         $slug
     );

输出段塞的总长度为68个字符:
/job/hello-this-is-my-job-posting-in-91770-rosemead-california-12345
或者为了更简单的处理而合并第一和第二组分:(Demo

echo preg_replace_callback(
         '~^((?:[^-]*-)*)(in-\d{5}-[^-]*-[^-]*-\d*)$~u',
         fn($m) => implode([
             preg_replace(
                 '~^.{0,' . ($slugLimit - mb_strlen($m[2]) - 1) . '}-\K.*~u',
                 '',
                 $m[1]
             ),
             $m[2]
         ]),
         $slug
     );

最后,我所能想到的最紧凑的版本在lookahead中使用了一个捕获组,以便在回调中替换完整的字符串匹配。Demo

echo preg_replace_callback(
         '~^(?:[^-]*-)*(?=(in-\d{5}-[^-]*-[^-]*-\d*)$)~u',
         fn($m) => preg_replace(
             '~^.{0,' . ($slugLimit - mb_strlen($m[1]) - 1) . '}-\K.*~u',
             '',
             $m[0]
         ),
         $slug
     );

如果检查新slug的mb_strlen(),它仍然超过限制,那么应该抛出异常或通知用户违规。

相关问题