實現一個方法 myTrim(String str),功能等同于 String.trim():移除字符串首尾的空白字符 (ASCII ≤ 0x20,即空格、制表符 \t、換行 \n、回車 \r 等),返回新字符串。中間空白保留。
注意:JDK 11+ String.strip() 使用 Unicode 空白字符判定 (Character.isWhitespace),範圍更廣。本文實現經典 trim() 邏輯 (ASCII ≤ 32)。
public class TrimImpl {
public static String myTrim(String str) {
if (str == null) return null; // 或拋 NPE,參考 String 行為
int len = str.length();
int start = 0;
int end = len - 1;
// 1. 從左向右找首個非空白字符
while (start <= end && str.charAt(start) <= ' ') { // ' ' = 32 (0x20)
start++;
}
// 2. 從右向左找首個非空白字符
while (end >= start && str.charAt(end) <= ' ') {
end--;
}
// 3. 全是空白 或 空字符串
if (start > end) {
return "";
}
// 4. 截取有效區間 [start, end] (substring 末尾索引不含)
return str.substring(start, end + 1);
}
// 測試驗證
public static void main(String[] args) {
String[] tests = {
" hello world ", // 普通首尾空格
"\t\n Java \r\n", // 混合空白字符
"NoTrim", // 無首尾空白
" ", // 全空白
"", // 空串
" a ", // 單字符兩側空格
" a b c " // 中間保留空格
};
for (String s : tests) {
String result = myTrim(s);
String expected = s.trim();
boolean pass = (result == null && expected == null) || (result != null && result.equals(expected));
System.out.printf("輸入: [%s] → 我: [%s] | JDK: [%s] | %s%n",
escape(s), escape(result), escape(expected), pass ? "✅" : "❌");
}
}
// 輔助:可視化空白字符
static String escape(String s) {
if (s == null) return "null";
return s.replace(" ", "·").replace("\t", "\\t").replace("\n", "\\n").replace("\r", "\\r");
}
}
| 步驟 | 操作 | 索引含義 | 終止條件 |
|---|---|---|---|
| 左掃描 | start++ | 指向第一個非空白字符 | start > end 或 char > ' ' |
| 右掃描 | end-- | 指向最後一個非空白字符 | end < start 或 char > ' ' |
| 判空 | start > end | 說明沒找到非空白字符 | 返回 "" |
| 截取 | substring(start, end+1) | 左閉右開,故 end+1 | 返回有效子串 |
// JDK 實現 (簡化)
public String trim() {
int len = value.length;
int st = 0;
char[] val = value; // 內部 char[] 或 byte[] (compact strings)
while ((st < len) && (val[st] <= ' ')) st++;
while ((st < len) && (val[len - 1] <= ' ')) len--;
return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}
異同點:
substring 截取。value (避免 charAt 方法調用開銷),若無需修剪直接返回 this (優化)。char[] 或 byte[] 直接索引 (如 JDK 源碼)。substring JDK 7+ 已無共享 (複製數組)。
public static String myStrip(String str) {
if (str == null) return null;
int len = str.length();
int start = 0, end = len - 1;
while (start <= end && Character.isWhitespace(str.charAt(start))) start++;
while (end >= start && Character.isWhitespace(str.charAt(end))) end--;
return (start > end) ? "" : str.substring(start, end + 1);
}
Character.isWhitespace 涵蓋:空格、控制字符 (U+0000~U+001F)、Unicode 空間分隔符 (U+2000~U+200A)、零寬空格 (U+200B) 等。
| 輸入類別 | 示例 | 預期輸出 | 驗證點 |
|---|---|---|---|
| 正常首尾空格 | " abc " | "abc" | 基本功能 |
| 混合空白字符 | "\t\n abc \r\n" | "abc" | 識別 \t\n\r |
| 無首尾空白 | "abc" | "abc" | 早期返回優化 |
| 全空白 | " \t\n" | "" | 邊界 start>end |
| 空字符串 | "" | "" | 長度 0 處理 |
| 單字符 | " a " | "a" | start==end 情況 |
| 中間空白 | " a b " | "a b" | 不誤刪中間 |
| null 輸入 | null | null / NPE | 防守性編程 |
| Unicode 空白 | "\u2003abc\u2003" | trim 保留 / strip 移除 | 區分 trim/strip |
手寫 trim() 核心是雙指針收斂 + ASCII ≤ 32 判定 + substring 截取。理解其邏輯有助於掌握字符串處理基本功、邊界條件防禦、以及 JDK 源碼優化思路 (內部數組訪問、早期返回)。實際開發**直接調用 JDK 方法**,但在面試、教學、嵌入式無標準庫場景下,手寫實現是考察編程基本功的經典題目。