處理中英文混合文本時,直接按字元數截取或分句極易產生亂碼(多位元組字元被截斷)或標點判斷錯誤(中英文標點混淆)。本文介紹一種「編碼轉換 + 正則匹配 + 解碼還原」的巧妙方案,完美解決中英文混排斷句難題。
| 原始字元 | urlencode 後 | 說明 |
| , | %2C | 英文逗號 |
| . | %2E (或保持 .) | 英文句號 |
| ? | %3F | 英文問號 |
| ! | %21 | 英文驚嘆號 |
| ; | %3B | 英文分號 |
| , | %EF%BC%8C | 中文逗號 (UTF-8) |
| 。 | %E3%80%82 | 中文句號 (UTF-8) |
| ? | %EF%BC%9F | 中文問號 (UTF-8) |
| ! | %EF%BC%81 | 中文驚嘆號 (UTF-8) |
| ; | %EF%BC%9B | 中文分號 (UTF-8) |
| ...... | %2E%2E%2E%2E%2E%2E (或 %E2%80%A6) | 省略號 |
完整實作程式碼
<?php
// 測試:查看標點編碼後樣貌
echo urlencode(',-.-?-!-;-,-。-?-!-;-......') . PHP_EOL;
// 待處理混合文本
$str = "測試測試,測試測試.測試測試?測試測試!測試測試;測試測試,測試測試。測試測試?測試測試!測試測試;測試測試......";
echo "原文:$str\n";
// 核心處理邏輯
$str = urlencode($str);
// 正則模式:匹配「任意字元(非貪婪) + 結尾標點」的組合
// \.{3,6} 匹配 3-6 個連續點號(處理省略號)
$pattern = '/(.*?)(\.{3,6}|%2C|\.|%3F|%21|%3B|%EF%BC%8C|%E3%80%82|%EF%BC%9F|%EF%BC%81|%EF%BC%9B)/';
preg_match_all($pattern, $str, $matches);
$sentences = [];
foreach ($matches[0] as $match) {
$sentences[] = urldecode($match);
}
var_dump($sentences);
/*
輸出結果:
array(10) {
[0]=> string(15) "測試測試,"
[1]=> string(15) "測試測試."
[2]=> string(15) "測試測試?"
[3]=> string(15) "測試測試!"
[4]=> string(15) "測試測試;"
[5]=> string(18) "測試測試,"
[6]=> string(18) "測試測試。"
[7]=> string(18) "測試測試?"
[8]=> string(18) "測試測試!"
[9]=> string(24) "測試測試......"
}
*/
?>
方案優勢分析
| 傳統 mb_substr / 正則直匹 | urlencode 方案 |
| 需處理多位元組邊界,易截斷字元 | 編碼後全為單位元組,無邊界問題 |
| 中英文標點需分別列舉,正則複雜 | 統一在編碼層面匹配,邏輯清晰 |
| 編碼轉換(UTF-8/GBK)需改代碼 | urlencode 自動適應當前腳本編碼 |
| 效能較低(mb_* 函數較慢) | 純字串操作,效能極佳 |
進階擴展:支援更多語言與標點
function split_sentences($text, $encoding = 'UTF-8') {
// 通用標點集(可擴展)
$punctuations = [
'.', '?', '!', ';', ':', ',', // 基礎拉丁
'。', '?', '!', ';', ':', ',', '、', // 中文
'.', '?', '!', ';', ':', ',', // 全形英文
'…', '...', '。。。', // 省略號變體
];
// 動態構建正則(需對特殊字元轉義)
$encoded_puncts = array_map(function($p) {
return preg_quote(urlencode($p), '/');
}, $punctuations);
$pattern = '/(.*?)(' . implode('|', $encoded_puncts) . ')/u';
$encoded = urlencode($text);
preg_match_all($pattern, $encoded, $matches);
return array_map('urldecode', $matches[0]);
}
適用場景與限制
- ✅ 適用:文章摘要生成、語音合成分句、關鍵詞提取前處理、郵件/簡訊內容分段
- ✅ 適用:UTF-8、GBK、BIG5 等任意編碼環境(urlencode 自適應)
- ⚠️ 注意:不處理引號內標點(如:「他說:『你好!』」會在 !處斷開)
- ⚠️ 注意:數字小數點(3.14)、網址、郵箱會被誤切,需預處理保護
- ❌ 不適用:需要語義理解的複雜 NLP 斷句(需用 jieba、spaCy 等工具)
總結
「urlencode + 正則 + urldecode」是一個極具工程智慧的「降維打擊」技巧:將複雜的多位元組字元邊界問題,轉化為簡單的 ASCII 字串模式匹配問題。代碼簡潔(核心 < 10 行)、效能優異、跨編碼相容、易於擴展。對於「按標點分句」這一高頻需求,是極具性價比的首選方案。
- 上一篇文章: 法國第一大新聞網站 LeMonde.fr 成功遷移 PHP:開源技術棧重構實戰案例
- 下一篇文章: PHP 記錄搜尋引擎蜘蛛爬蟲日誌:Baidu、Google、Bing、Yahoo、Soso、Sogou、Yodao 完整識別與記錄
Copyright ©
程式碼之家 All Rights Reserved