4 回答

TA貢獻1852條經驗 獲得超1個贊
我認為非正則表達式沒問題。
此方法遍歷一半的字符串并嘗試查找如果在 str_replace 中使用則不返回任何內容的子字符串。
如果我們發現了,那么我們就知道這是一個重復的詞。
$str = 'feetfeetfeet';
$return = $str; // return full str if it fails
$len = strlen($str);
for($i = 1; $i < $len/2; $i++){
$sub = substr($str, 0, $i);
if(str_replace($sub, "", $str) == ""){
$return = $sub;
break;
}
}
echo $return; //feet

TA貢獻1817條經驗 獲得超14個贊
這看起來類似于查找也是后綴的最長公共前綴?,F在,這
length - longest prefix which is also a suffix
就是您的答案。你可以從這個找到構建前綴后綴表的算法KMP pattern matching algorithm
。時間復雜度為
O(n)
,空間復雜度為O(n)
。
片段:
<?php
$str = "feetfeetfeet";
$length = strlen($str);
$prefix_suffix_table = array_fill(0, $length, 0);
$j = 0;
for($i = 1; $i < $length; ++$i){
? ? while($j > 0 && $str[$i] != $str[$j]){
? ? ? ? $j = $prefix_suffix_table[$j - 1];
? ? }
? ? if($str[$i] == $str[$j]){
? ? ? ? $prefix_suffix_table[$i] = ++$j;
? ? }
}
echo substr($str, 0, $length - end($prefix_suffix_table));
注意:如果您的字符串格式不正確,例如xyz
沒有重復的子字符串,您可以使用添加額外的檢查str_repeat()
并在需要時拋出異常。

TA貢獻1834條經驗 獲得超8個贊
我已經想出如何使用正則表達式來做到這一點。盡管我已經意識到它可能對我的目的沒有用,因為 mmmm 可以是 2x mm(毫米)或 4x m(米)。雖然如果我只關心最多支持 3 次重復,我可以使用:
if(preg_match('/^([a-z]*)\1{2}$/', $input, $matches)) {
$repeating = $matches[1];
$reps = 3;
} elseif(if(preg_match('/^([a-z]*)\1$/', $input, $matches)) {
$repeating = $matches[1];
$reps = 2;
} else {
$repeating = $input;
$reps = 1;
}
并不是說下面會把字符串分成最小的重復素數:
preg_match('/^([a-z]*)\1+$/', $input, $matches);
$repeating = $matches[1];
這是此輸出的表格:
┌────────────┬────────────┐
│ $input │ $repeating │
├────────────┼────────────┤
│ mm │ m │
│ mmm │ m │
│ mmmm │ mm │
│ mmmmm │ m │
│ mmmmmm │ mmm │
│ mmmmmmm │ m │
│ mmmmmmmm │ mmmm │
│ mmmmmmmmm │ mmm │
│ mmmmmmmmmm │ mmmmm │
└────────────┴────────────┘
因為只考慮最小的素數細分
preg_match('/^([a-z]*)\1{1,2}$/', $input, $matches)
不合適,因為它會像上表一樣,發現 'mmmmmm' 的重復部分是 'mmm' 而不是所需的 mm。
我在開頭提供的三個案例實施是我目前正在使用的,因為我的輸入通常是產品的年齡組或維度,我還沒有看到產品被描述為超過三個維度或年齡組,'11yr,12yr,13yr,14yr'雖然我可以想象像后者這樣的事情,無論多么罕見,最終都會發生。因此,我可能會放棄這種方法,轉而使用 preg_match_all 從包含數字的原始字符串中提取單位:
preg_match_all('/([0-9]+)\s*([a-z]*)\s*/', $input, $matches)
然而,如果其他人實際上有興趣找到最小的重復子字符串(所以 'm' 代表 'mmmm'),這可以通過循環中的正則表達式來完成:
$repeating = $input;
while(preg_match('/^([a-z]*)\1+$/', $repeating, $matches)) {
$repeating = $matches[1];
}
這將產生:
┌────────────┬────────────┐
│ $input │ $repeating │
├────────────┼────────────┤
│ mm │ m │
│ mmm │ m │
│ mmmm │ m │
│ mmmmm │ m │
│ mmmmmm │ m │
│ mmmmmmm │ m │
│ mmmmmmmm │ m │
│ mmmmmmmmm │ m │
│ mmmmmmmmmm │ m │
│ cmcm │ cm │
│ cmcmcm │ cm │
│ cmcmcmcm │ cm │
│ cmcmcmcmcm │ cm │
└────────────┴────────────┘

TA貢獻1793條經驗 獲得超6個贊
您還可以使用str_split()將字符串轉換為數組并找到其唯一元素,然后再次返回將所有唯一元素內爆在一起。
<?php
$str = array_unique(str_split('ageage'));
$result = implode($str);
?>
輸出
age
- 4 回答
- 0 關注
- 162 瀏覽
添加回答
舉報