函數實作
function get_between(string $input, string $start, string $end): string
{
$startPos = strpos($input, $start);
if ($startPos === false) return '';
$startPos += strlen($start);
$endPos = strpos($input, $end, $startPos);
if ($endPos === false) return '';
return substr($input, $startPos, $endPos - $startPos);
}
// 測試
$string = "www.jb51.net";
echo get_between($string, "www.", ".net"); // jb51
原版程式碼問題分析
// 原版有誤:使用負長度計算容易出錯
$substr = substr($input, strlen($start)+strpos($input, $start),
(strlen($input) - strpos($input, $end))*(-1));
// 當 $end 在 $start 之前、或多次出現時會產生錯誤結果
關鍵限制:分隔符必須唯一
$url = "https://www.jb51.net/";
echo get_between($url, "https://", "/");
// 預期:www.jb51.net
// 實際:空字串(因為第一個 '/' 在 'https://' 內部)
// 原因:strpos 找到第一個 '/' 位置 5,早於 'www' 起始位置
改良版:支援指定第 N 次出現
function get_between_advanced(
string $input,
string $start,
string $end,
int $startOccurrence = 1,
int $endOccurrence = 1
): string
{
// 找第 N 個 $start
$pos = -1;
for ($i = 0; $i < $startOccurrence; $i++) {
$pos = strpos($input, $start, $pos + 1);
if ($pos === false) return '';
}
$startPos = $pos + strlen($start);
// 找第 N 個 $end(從 $startPos 之後開始)
$pos = $startPos - 1;
for ($i = 0; $i < $endOccurrence; $i++) {
$pos = strpos($input, $end, $pos + 1);
if ($pos === false) return '';
}
$endPos = $pos;
return substr($input, $startPos, $endPos - $startPos);
}
// URL 解析範例
$url = "https://api.example.com/v1/users/123/profile";
echo get_between_advanced($url, "/", "/", 3, 1); // v1
echo get_between_advanced($url, "/", "/", 4, 1); // users
echo get_between_advanced($url, "/", "/", 5, 1); // 123
正則表達式替代方案
function get_between_regex(string $input, string $start, string $end): ?string
{
// 逃脫特殊字元
$start = preg_quote($start, '/');
$end = preg_quote($end, '/');
// 非貪婪匹配
if (preg_match("/{$start}(.*?){$end}/s", $input, $matches)) {
return $matches[1];
}
return null;
}
// 多段擷取
$html = '內容1
內容2
';
preg_match_all('/(.*?)<\/div>/s', $html, $matches);
print_r($matches[1]); // ['內容1', '內容2']
效能比較與選擇建議
| 方法 | 速度 | 可讀性 | 適用場景 |
| strpos + substr | 最快 | 中 | 固定格式、高頻呼叫、分隔符唯一 |
| preg_match | 較慢 | 高 | 複雜模式、多段擷取、分隔符可能重複 |
| strstr/strchr | 快 | 中 | 只需「從某字元到結尾」或「開頭到某字元」 |
實戰:解析標準 URL 組件
// 不要自己寫解析,用內建函數
$url = "https://user:pass@api.example.com:8080/v1/users/123?sort=name#section";
$parts = parse_url($url);
/*
Array
(
[scheme] => https
[host] => api.example.com
[port] => 8080
[user] => user
[pass] => pass
[path] => /v1/users/123
[query] => sort=name
[fragment] => section
)
*/
// 取路徑段落
$segments = explode('/', trim($parts['path'], '/'));
// ['v1', 'users', '123']
- 上一篇文章: PHP 多維數組按指定鍵值排序:uasort + 自定義比較函數實戰
- 下一篇文章: PHP 數組索引鍵名加引號與不加引號的區別:常量解析陷阱