String.StartsWith与 EndsWith在大量使用时效率果然极低

今天在写一个工具时,写着写着发现执行速度突然变慢。最后发现是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;
    }

}

 

posted @ 2021-01-02 20:11  时空观察者9号  阅读(642)  评论(0编辑  收藏  举报