1. 程式人生 > 其它 >String.StartsWith與 EndsWith在大量使用時效率果然極低

String.StartsWith與 EndsWith在大量使用時效率果然極低

技術標籤:pythonjavamysqldebuglinux

今天在寫一個工具時,寫著寫著發現執行速度突然變慢。最後發現是string.StartsWith與EndsWith的鍋,改為手動比較後,執行時間變成原來的1/5-1/10。程式碼如下 ,黃色背景是主要部分

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Threading;
using System.Text.RegularExpressions;
using System;

public class XLogicCodeCheck
{

    [MenuItem("程式碼檢查/邏輯層程式碼檢查")]
    public static void StartLogicCodeCheck()
    {
        Debug.Log("邏輯層程式碼檢查");

        var path = "Assets/Scripts/Logic";
        var files = Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories);

        var total = 0.0f;
        var totalFind = 0;
        var errLines = new List<string>(100);
        foreach (var item in files)
        {
            var allines = File.ReadAllLines(item);
            if(allines.Length > 0 && allines[0].Trim().StartsWith("//Float_Uncheck"))
            {//Float_Uncheck
                continue;
            }

            for (int i = 0; i < allines.Length; ++i)
            {
                var ltext = allines[i].Trim();
                if (CheckLine(allines, i))
                {
                    var info = $"發現有問題程式碼,檔案:{item}, 行:{i + 1},  {ltext}";
                    EditorUtility.DisplayDialog("邏輯層程式碼檢查", info, "確定");
                    errLines.Add(info);
                    totalFind++;
                }
            }

            EditorUtility.DisplayProgressBar("邏輯層程式碼檢查", $"進度:", total++ / files.Length);
        }

        if (totalFind == 0)
        {
            EditorUtility.DisplayDialog("邏輯層程式碼檢查", "檢查完成,沒有發現問題", "確定");
        }
        else
        {
            var savePath = "Assets/FloatCheck.txt";
            EditorUtility.DisplayDialog("邏輯層程式碼檢查", $"檢查完成,共發現{totalFind}處問題,已儲存到檔案:{savePath}", "確定");

            File.WriteAllLines(savePath, errLines);
        }

        Debug.Log("邏輯層程式碼檢查完成");

    }

    static string[] rules = new string[] {
            @"[\s(]float[\s)]", @"[\s(]double[\s)]", @"\d+\.\d+",  //float, double, 浮點數值
            @"\sMath\.[a-zA-Z]+\s*\(", @"\sMathf\.[a-zA-Z]+\s*\(", //Math或Mathf相關API
            @"new\s+Random\s*\(",@"new\s+System\s*\.\s*Random\s*\(", @"Random\s*\.\s*RandomRange\s*\(", @"Random\s*\.\s*Range\s*\(", @"Random\s*\.\s*ColorHSV\s*\(",//隨機數
        };

    static string[] excludeRules = new string[] { "Math.Max", "Math.Min", "Math.Abs" }; //排除項,不檢查這些
    private static bool CheckLine(string[] allines, int iline)
    {
        var codeStr = FilterComment(allines, iline).Trim();
        if (codeStr.Length <= 0) return false;

        foreach (var item in rules)
        {
            var matches = Regex.Matches(codeStr, item);
            foreach (Match match in matches)
            {
                var isok = true;
                foreach (var exc in excludeRules)
                {
                    if (match.Value.Contains(exc)) isok = false;
                }

                if (isok) return true;
            }

        }

        return false;
    }

    //過濾掉註釋
    private static string FilterComment(string[] allines, int iline)
    {
        if (InBlockComment(allines, iline)) return "";

        var codeStr = allines[iline];
        if (codeStr.Contains("Float_Uncheck") || codeStr.StartsWith("//") || codeStr.StartsWith("/*") || codeStr.StartsWith("#region"))
        {
            return "";
        }

        //去除行中註釋
        var cmtIdx = codeStr.IndexOf("//");
        if (cmtIdx < 0)
        {
            cmtIdx = codeStr.IndexOf("/*");
        }
        if (cmtIdx >= 0)
        {
            codeStr = codeStr.Substring(0, cmtIdx);
        }

        return codeStr;
    }

    //是否在塊註釋中
    private static bool InBlockComment(string[] allines, int iline)
    {
        for (int i = iline-1; i>=0; --i)
        {
            var line = allines[i];
            var lineLen = line.Length;
            if(lineLen >= 2)
            {
                if (line[lineLen - 2] == '*' && line[lineLen - 1] == '/')
                {//line.EndsWith("*/"),這個函式非常低效
                    return false;
                }
                else if (line[0] == '/' && line[1] == '*')
                {//line.StartsWith("*/"),這個函式非常低效
                    return true;
                }
            }
        }

        return false;
    }

}