利用查找替换批处理(附完整源码),进行高效重构

如果你需要在大量的代码文件中修改某个地方,那么最高效的办法就是使用正则进行批量处理。

下面介绍一个C#写的查找替换处理程序。

我本人不喜欢太多的废话,看过功能介绍,各位朋友感兴趣,直接下载小源码包或程序跑一通,就了解了。

主窗体


说明

目录: 指定批处理操作的执行目录。

子目录:如果勾选,将处理所有子孙级目录的文件。

文件筛选:与在Windows资源管理器上的搜索文件输入的规则一样。常用的就是星号加后缀名,比如*.cs 。

查找内容:可输入正则表达式或者文本。

替换内容:可以输入用于替换的文本。可以使用{N}占位,以进行后向引用操作。N序号从1开始,0表示匹配到的整个字符串。

正则:勾选,表示使用正则进行处理,否则使用文本进行处理。

处理结果窗体

 

双击选项可以打开文件

代码

 主窗体代码

View Code
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;

namespace AFReplace
{
    public partial class FrmAFReplace : Form
    {
        private string _basePath;
        private string _findContent;
        private string _filter;
        private string _replacement;
        private bool _replaceWithRegex;
        private delegate void DealDelegate(string workPath);

        private List<KeyValue> _lsDealFilesResult;
        /// <summary>
        
/// 查找或替换的操作委托
        
/// </summary>
        private DealDelegate _delWork;
        /// <summary>
        
/// 当前是否为替换的处理操作
        
/// </summary>
        private bool _isReplaceDeal;


        public FrmAFReplace()
        {
            InitializeComponent();
            Icon = Properties.Resources.file_edit_2;
        }

        private void btnReplace_Click(object sender, EventArgs e)
        {
            _isReplaceDeal = true;
            _delWork = ReplaceContent;
            Work();
        }
        private void Work()
        {
            _basePath = txtDirectory.Text;
            if (!Directory.Exists(_basePath))
            {
                tsslblMessage.Text = "路径不存在";
                return;
            }

            DirectoryInfo basePathInfo = new DirectoryInfo(_basePath);

            _filter = txtFilter.Text;
            if (string.IsNullOrEmpty(_filter))
            {
                tsslblMessage.Text = "文件筛选输入为空";
                return;
            }
            _findContent = txtFindContent.Text;
            if (string.IsNullOrEmpty(_findContent))
            {
                tsslblMessage.Text = "查找内容输入为空";
                return;
            }
            _replacement = txtReplaceContent.Text;
            _replaceWithRegex = ckbReplaceWithRegex.Checked;
            _lsDealFilesResult = new List<KeyValue>();
            if (ckbDirectoryItem.Checked)
            {
                new Thread(() => WorkInDirectoryDeep(basePathInfo)).Start();
            }
            else
            {
                new Thread(() => WorkInDirectory(basePathInfo)).Start();
            }
        }
        /// <summary>
        
/// 仅在指定目录替换
        
/// </summary>
        
/// <param name="dirInfo"></param>
        private void WorkInDirectory(DirectoryInfo dirInfo)
        {
            WorkByDirectoryInfo(dirInfo);
            WorkedAfter();
        }
        private void WorkByDirectoryInfo(DirectoryInfo dirInfo)
        {
            if (dirInfo.Exists)
            {
                _delWork(dirInfo.FullName);
            }
        }
        private void WorkedAfter()
        {
            ShowFindResult();
        }
        /// <summary>
        
/// 深入到子目录替换
        
/// </summary>
        
/// <param name="dirInfo"></param>
        private void WorkInDirectoryDeep(DirectoryInfo dirInfo)
        {
            WorkByDirectoryInfo(dirInfo);
            DirectoryInfo[] lsDirInfo = dirInfo.GetDirectories();
            if (lsDirInfo.Length > 0)
            {
                foreach (DirectoryInfo info in lsDirInfo)
                {
                    WorkInDirectory(info);
                }
            }
            else
            {
                ShowMessage("操作完成");
                WorkedAfter();
            }
        }
        /// <summary>
        
/// 在指定目录查找指定文件,并替换,保存。
        
/// </summary>
        
/// <param name="workPath"></param>
        private void ReplaceContent(string workPath)
        {
            string[] files = Directory.GetFiles(workPath, _filter);
            string value;
            foreach (string file in files)
            {
                string content = File.ReadAllText(file);
                content = _replaceWithRegex ? Regex.Replace(content, _findContent, ReplaceDeal) : content.Replace(_findContent, _replacement);
                byte[] buffer = Encoding.UTF8.GetBytes(content);
                if (new FileInfo(file).IsReadOnly)
                {
                    value = "文件只读 > " + Path.GetFileName(file);
                }
                else
                {
                    File.Delete(file);

                    using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write))
                    {
                        fs.Write(buffer, 0, buffer.Length);
                    }
                    value = "已处理 > " + Path.GetFileName(file);


                }
                ShowMessage(value);
                _lsDealFilesResult.Add(new KeyValue(file, value));
            }
        }
        /// <summary>
        
/// 在指定目录查找指定文件
        
/// </summary>
        
/// <param name="workPath"></param>
        private void FindFiles(string workPath)
        {
            string[] files = Directory.GetFiles(workPath, _filter);
            foreach (string file in files)
            {
                string content = File.ReadAllText(file);
                bool isMatch = _replaceWithRegex ? Regex.IsMatch(content, _findContent) : content.Contains(_findContent);
                if (isMatch)
                {
                    _lsDealFilesResult.Add(new KeyValue(file, file));
                }
            }
        }
        /// <summary>
        
/// 正则替换
        
/// </summary>
        
/// <param name="m"></param>
        
/// <returns></returns>
        private string ReplaceDeal(Match m)
        {
            if (m.Success)
            {
                MatchCollection mc = Regex.Matches(_replacement, @"{(?<value>\d+)}");
                List<int> lsValueIndex = new List<int>();
                foreach (Match match in mc)
                {

                    int iValueIndex = int.Parse(match.Groups["value"].Value);
                    //序号不可以大于查找到的集合数,总数为匹配()数+自身1
                    if (iValueIndex > m.Groups.Count)
                        throw new Exception("替换的匹配数错误");

                    if (!lsValueIndex.Contains(iValueIndex))
                        lsValueIndex.Add(iValueIndex);
                }
                return lsValueIndex.Aggregate(_replacement, (current, i) => current.Replace("{" + i + "}", m.Groups[i].Value));
            }
            return "";
        }
        private void ShowMessage(string msg)
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(() => ShowMessage(msg)));
            }
            else
            {
                tsslblMessage.Text = msg;
            }
        }
        private void ShowFindResult()
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(ShowFindResult));
            }
            else
            {
                new FrmDealResult(_lsDealFilesResult, _isReplaceDeal ? "替换结果" : "查找结果").Show();
            }
        }


        private void lblAbout_Click(object sender, EventArgs e)
        {
            MessageBox.Show("bug及建议提交,请联系alifellod@163.com""查找替换", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void ckbReplaceWithRegex_CheckedChanged(object sender, EventArgs e)
        {
            toolTip1.SetToolTip(txtReplaceContent,
                                ckbReplaceWithRegex.Checked ? "可以使用{index}进行后向引用,{1}{2}={2}{1}。序号从1开始,0为匹配到的整个值。" : "");
        }

        private void btnFind_Click(object sender, EventArgs e)
        {
            _isReplaceDeal = false;
            _delWork = FindFiles;
            Work();
        }

        private void txtDirectory_TextChanged(object sender, EventArgs e)
        {
            toolTip1.SetToolTip(txtDirectory, txtDirectory.Text.Length > 45 ? txtDirectory.Text : "");
        }

        private void tsslblViewDealList_Click(object sender, EventArgs e)
        {
            ShowFindResult();
        }

        private void btnOpenDirectory_Click(object sender, EventArgs e)
        {
            if (Directory.Exists(txtDirectory.Text))
            {
                Process.Start(txtDirectory.Text);
            }
        }

        private void btnSelectDirectory_Click(object sender, EventArgs e)
        {
            var fbd = new FolderBrowserDialog();
            if (fbd.ShowDialog() == DialogResult.OK)
            {
                txtDirectory.Text = fbd.SelectedPath;
            }
        }
    }
}

处理结果窗体代码

  

View Code
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;

namespace AFReplace
{
    public partial class FrmDealResult : Form
    {
        public FrmDealResult(List<KeyValue> filePtahs, string formTitle)
        {
            InitializeComponent();
            Text = formTitle;
            Icon = Properties.Resources.window;
            if (filePtahs != null && filePtahs.Count > 0)
            {
                filePtahs.Sort((o1, o2) => String.Compare(o1.Value, o2.Value, StringComparison.Ordinal));

                lsbResults.DisplayMember = "Value";
                lsbResults.ValueMember = "Key";
                lsbResults.DataSource = filePtahs;
                tsslblMessage.Text = "共计记录: " + filePtahs.Count + " 条";
            }
        }

        public override sealed string Text
        {
            get { return base.Text; }
            set { base.Text = value; }
        }

        private void lsbResults_DoubleClick(object sender, EventArgs e)
        {
            if (lsbResults.SelectedItem != null)
            {
                string filePath = ((KeyValue)lsbResults.SelectedItem).Key;
                if (File.Exists(filePath))
                {
                    Process.Start(filePath);
                }
                else
                {
                    tsslblMessage.Text = "文件不存在";
                }
            }
        }
    }
}

 

辅助类类名

View Code
namespace AFReplace
{
    public class KeyValue
    {
        /// <summary>
        
/// 保存文件路径
        
/// </summary>
        public string Key { getset; }
        /// <summary>
        
/// 显示的文本
        
/// </summary>
        public string Value { getset; }
        public KeyValue(string key, string value)
        {
            Key = key;
            Value = value;
        }
    }
}

下载

源码下载

https://files.cnblogs.com/yelaiju/AFReplace_src.rar

可执行文件下载

https://files.cnblogs.com/yelaiju/AFReplacer.rar  

原文地址:https://www.cnblogs.com/yelaiju/p/3055586.html