首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

手寫實現 String.trim() 核心邏輯:去除首尾空白字符的算法詳解

     編輯:Java 相關知識

需求分析

實現一個方法 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 源碼對比 (JDK 17 java.lang.String)


// 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;
}

異同點:

  • 相同:雙指針邏輯、ASCII ≤ 32 判定、substring 截取。
  • 不同:JDK 直接操作內部數組 value (避免 charAt 方法調用開銷),若無需修剪直接返回 this (優化)。

性能優化方向

  1. 避免 charAt 調用:轉 char[] 或 byte[] 直接索引 (如 JDK 源碼)。
  2. 早期返回:檢測首尾字符非空白時直接返回原字符串。
  3. 緩存結果:不可變字符串天然支持結構共享,但 substring JDK 7+ 已無共享 (複製數組)。

擴展:實現 strip() (Unicode 感知)


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 輸入nullnull / NPE防守性編程
Unicode 空白"\u2003abc\u2003"trim 保留 / strip 移除區分 trim/strip

總結

手寫 trim() 核心是雙指針收斂 + ASCII ≤ 32 判定 + substring 截取。理解其邏輯有助於掌握字符串處理基本功、邊界條件防禦、以及 JDK 源碼優化思路 (內部數組訪問、早期返回)。實際開發**直接調用 JDK 方法**,但在面試、教學、嵌入式無標準庫場景下,手寫實現是考察編程基本功的經典題目。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved