聊聊c#字元串拼接

来源:https://www.cnblogs.com/team-xiong/archive/2019/12/27/12107502.html
-Advertisement-
Play Games

字元串對我編程人員來說是字元串時每天見面的常客,你不認識不熟悉他都不得行,字元串的拼接更是家常便飯,那麼在實際開發過程中實現字元串的拼接有哪一些方式呢?咱們一起來聊聊,來交流溝通,學習一波。也許你會說,那也太簡單了嘛,誰不會啊,哈哈,使用起來確實簡單,但是不一定我們都使用的方式還有優秀的方式嗎? 在 ...


字元串對我編程人員來說是字元串時每天見面的常客,你不認識不熟悉他都不得行,字元串的拼接更是家常便飯,那麼在實際開發過程中實現字元串的拼接有哪一些方式呢?咱們一起來聊聊,來交流溝通,學習一波。也許你會說,那也太簡單了嘛,誰不會啊,哈哈,使用起來確實簡單,但是不一定我們都使用的方式還有優秀的方式嗎?

    在文章前,我們先簡單聊聊關於string的數據類型存儲必須瞭解概念:

    string是一個引用類型,是一個sealed類,存儲在堆記憶體上,每一次修改都會從新創建一個新的string來存儲,原始的會自動被回收。這個是不感覺是廢話,人人都知道嘛,哈哈哈。

    下麵以c#為開發語言來說明:實現字元串的拼接常用的方式有如下四種

 

其一、直接通過+拼接

    直接通過+拼接是我們在代碼中最常見的一種方式,下麵以一個簡單的代碼段來分析分析

1     string str="1";
2 
3     str=str+"2";

    第一段代碼,首先分配了一個記憶體空間來存儲str變數,其值為“1”

    第二段代碼,重新分配了一個新的記憶體空間來存儲“12”,並將str指向新地址

    通過分析,其實我們不難發現,兩端就簡單的代碼,就會有兩次記憶體地址操作,隨著拼接字元串的個數地址,分配記憶體地址的次數也遞增,當幾個簡單的字元串通過該方式拼接時,其實我們還是感覺不到性能的影響,但是當字元串數量大時,你都會有感覺了,那樣不僅僅造成記憶體的浪費,還直接影響性能。

所以在實際開發工程中,通過+拼接字元串比較常見,但是如果只是見到這種方式也就不那麼友好了,既然不友好,那麼顯然就會有比較友好的方式啦,下麵我們就分析分析通過StringBuilder來實現字元串的拼接。

 

其二、通過StringBuilder拼接字元串

 

    StringBuilder其實內部相當於是維護的一個字元數組,是一個可以動態增加自身數據長度,其預設長度為16,當存儲的字元串超出其長度是,會自動擴容2倍長度。

    哈哈,說到這兒,估計你看出了問題,那就是超出長度自動擴容,自動擴容是不是也需要犧牲性能,當然在幾次擴容你還感覺不到性能的影響,但是如果詞數多了,你就會感覺很明顯,這也是對StringBuilder的一些使用技巧。

我們去看不同小伙伴的代碼,你就會發現,技術老鳥,在初始化StringBuilder的時候會根據預估將要存儲的字元串大小,給StringBuilder初始化一個長度,這也就是細節上的差距體現。

    說了半天的廢話,是不是要來的實際的代碼來證明說的不是廢話呢?不急不急,在文章最後,我會專門寫測試代碼對比分析的。

 

其三、string.Format不陌生吧

 

    對於一些格式的數據拼接填充,string.Format也是經常看見的,他的一個很大好處就是,看上去比較清晰

    其實我們看過string的底層實現我們會發現,其底層本質還是StringBuilder來實現的

    下麵就是string.format的源碼實現

複製代碼
public static String Format(IFormatProvider provider, String format, params Object[] args) <br>{

    if (format == null || args == null)

      throw new ArgumentNullException((format==null)?"format":"args");

    StringBuilder sb = new StringBuilder(format.Length + args.Length * 8);

    sb.AppendFormat(provider,format,args);

    return sb.ToString();

}
複製代碼

 

    其實string.Format使用起來很簡單,我就不在啰嗦介紹了,免得大家覺得煩,哈哈哈

    string result=string.Format("大家好,我叫{0},今年{1}","程式員修煉之旅",1);

 

其四、$方式拼接字元串

 

    C#6.0出現了$方式拼接字元串,其實簡單說就是string.Format簡化操作版,string.Format如果拼接的字元串太多,估計自己都懵逼的分不清對應關係了,不知道你們遇到過沒有,反正我原來是遇到過的。$就很好的規避了該問題,那麼下    面來一個例子說明一切:

    

string name = "程式員修煉之旅";​    
int age = 1;​    
string str = string.Format("my name is{0}, I'm {1} years old",name,age);​    
string str2 = $"my name is{name}, I'm {age} years old";​    
最終結果是:str=str1

其五,當然還有其他方式,不在此啰嗦了,後續在討論

 

測試分析

    說了半天,不拿點實際東西來測試,我知道你是不會信服的,下麵就直接上測試代碼:

複製代碼
using System;
using System.Diagnostics;
using System.Text;

namespace stringSplicingTest
{
    /// <summary>
    /// 字元串拼接練習
    /// </summary>
    public class Program
    {
        /// <summary>
        /// 主函數入口
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            // 測試分別通過+ 和 StringBuilder 來連接 0 之100的數字
            Console.WriteLine("測試分別通過+ 和 StringBuilder 來連接");
            Console.WriteLine("");
            Console.WriteLine("測試連接 0 - 100 的數字");
            Console.WriteLine("");
            PlusString(100);
            StringBuilderString2(100);
            Console.WriteLine("");

            Console.WriteLine("");
            Console.WriteLine("測試連接 0 - 10000 的數字");
            PlusString(10000);
            StringBuilderString2(10000);
            Console.WriteLine("");
            Console.WriteLine("");

            // 下麵測試一下同樣是StringBuilder連接字元串,一個是定義吃指定長度,一個是不指定長度對比
            Console.WriteLine(@"下麵測試一下同樣是StringBuilder連接字元串, 一個是定義並指定長度,一個是不指定長度對比");
            Console.WriteLine("");
            Console.WriteLine("測試連接 0 - 1000000 的數字");
            Console.WriteLine("不初始化長度");
            StringBuilderString(1000000);
            Console.WriteLine("初始化長度");
            StringBuilderString2(1000000);

            Console.WriteLine("");
            Console.WriteLine("");

            Console.WriteLine("測試連接 0 - 10000000 的數字");
            Console.WriteLine("不初始化長度");
            StringBuilderString(10000000);
            Console.WriteLine("初始化長度");
            StringBuilderString2(10000000);

            Console.ReadLine();
        }

        /// <summary>
        /// 通過+拼接字元串
        /// </summary>
        /// <param name="totalNum"></param>
        private static void PlusString(int totalNum)
        {
            //// 定義一個秒錶,執行獲取執行時間
            Stopwatch st = new Stopwatch();//實例化類
            st.Start();//開始計時

            Console.WriteLine("開始執行,通過+連接字元串:");
            string result = "";
            //// 定義一個數組
            for (int i = 0; i < totalNum; i++)
            {
                result = result + i.ToString();
            }

            //需要統計時間的代碼段

            st.Stop();//終止計時
            Console.WriteLine(string.Format("執行完畢,通過+連接字元串!總耗時{0}毫秒",
            st.ElapsedMilliseconds.ToString()));
        }

        /// <summary>
        /// 通過s拼接字元串
        /// </summary>
        /// <param name="totalNum"></param>
        private static void StringBuilderString(int totalNum)
        {
            //// 定義一個秒錶,執行獲取執行時間
            Stopwatch st = new Stopwatch();//實例化類
            st.Start();//開始計時

            Console.WriteLine("開始執行,通過 StringBuilder 連接字元串:");

            StringBuilder result = new StringBuilder();

            //// 定義一個數組
            for (int i = 0; i < totalNum; i++)
            {
                result.Append(i.ToString());
            }

            string result2 = result.ToString();
            //需要統計時間的代碼段

            st.Stop();//終止計時
            Console.WriteLine(string.Format("執行完畢,通過 StringBuilder 連接字元串!總耗時{0}毫秒",
            st.ElapsedMilliseconds.ToString()));
        }


        /// <summary>
        /// 通過StringBuilder拼接字元串,初始化時指定一個長度
        /// </summary>
        /// <param name="totalNum"></param>
        private static void StringBuilderString2(int totalNum)
        {
            //// 定義一個秒錶,執行獲取執行時間
            Stopwatch st = new Stopwatch();//實例化類
            st.Start();//開始計時

            Console.WriteLine("開始執行,通過 StringBuilder 連接字元串:");

            StringBuilder result = new StringBuilder(totalNum * 6);

            //// 定義一個數組
            for (int i = 0; i < totalNum; i++)
            {
                result.Append(i.ToString());
            }

            string result2 = result.ToString();
            //需要統計時間的代碼段

            st.Stop();//終止計時
            Console.WriteLine(string.Format("執行完畢,通過 StringBuilder 連接字元串!總耗時{0}毫秒",
            st.ElapsedMilliseconds.ToString()));
        }
    }
}
複製代碼

 


 

結果分析總結:

測試分兩個點:

其一測試的是:通過+和StringBuilder拼接字元串的性能比較哦

其二測試的是:StringBuilder初始化長度和不初始化長度的性能比較

大概得出以下幾點結論

1、在待拼接的字元串少的時,+和StringBuilder沒有明顯的性能差距

2、當拼接的字元串多時,StringBuilder的優勢越來越明顯

3、同樣是StringBuilder拼接字元串,預估初始化長度的效率比不初始化指定長度的效率高

說到此,我相信大家都知道該怎麼使用了。好了,時間不早了,趕緊洗洗睡了,明天還得上班呢?

 END

 原文地址:https://www.cnblogs.com/xiaoXuZhi/p/XYH_String2.html

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • python記錄點 文件編碼 Unicode使用最少2個位元組(1個位元組=1BYTE=8bit=一個長度為8的二進位數) 來表示字母和符號等,有時候是4個位元組。 UTF-8是對Unicode編碼的壓縮和優化,最大的特點是它採用了變長的編碼方式,他不再是最少使用2個位元組,而是將所有的字元進行分類。asc ...
  • 1 堆設置 -Xms:初始堆大小 -Xmx:最大堆大小 -XX:NewSize=n:設置年輕代大小 -XX:NewRatio=n:設置年輕代和年老代的比值。如:為3,表示年輕代與年老代比值為1:3,年輕代占整個年輕代年老代和的1/4 -XX:SurvivorRatio=n:年輕代中Eden區與兩個S ...
  • WEB-INF是Java Web應用的安全目錄,在部署時用於存放class文件、項目用到的庫(jar包)、Java Web應用的配置文件web.xml。 瀏覽器不能訪問此目錄下的資源,比如在WEB-INF下放一些圖片,然後在jsp中用<img>來顯示這些圖片,是顯示不出來的。用<a>鏈接或者URI訪 ...
  • 這個場景跟《手寫Unity容器--極致簡陋版Unity容器》不同,這裡構造AndroidPhone的時候,AndroidPhone依賴於1個IPad 1、IPhone介面 2、AndroidPhone實現 3、IPad介面 4、IPad實現 5、IHeadPhone介面 6、IHeadPhone實現 ...
  • 本筆記摘抄自:https://www.cnblogs.com/liqingwen/p/5816051.html,記錄一下學習過程以備後續查用。 許多文件系統操作實質上是查詢,因此非常適合使用LINQ方法。 一、查詢具有指定屬性或名稱的文件 此示例演示如何查找指定目錄樹中具有指定文件擴展名(例如“.t ...
  • 首先使用PL/SQL 通過語句:select * from v$version; 查詢出使用的oracle版本,弄到對應版本的Oracle.DataAccess.DLL 我本地使用版本為:11.2.0.4.0 (64位)Oracle.DataAccess.DLL下載地址:https://www.or ...
  • 在很多系統中都用到導出,使用過多種導出方式,覺得ClosedXML插件的導出簡單又方便。 並且ClosedXML、DocumentFormat.OpenXml都是MIT開源。 ...
  • 場景 在ZedGraph的曲線圖上,雙擊圖時會在圖形上生成箭頭符號標記。 效果 註: 博客主頁: https://blog.csdn.net/badao_liumang_qizhi 關註公眾號 霸道的程式猿 獲取編程相關電子書、教程推送與免費下載。 實現 首先在ZedGraph所在的窗體的load事 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...