Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Text Line Remover - Remove Lines Containing Specific Words

3.30/5 (9 votes)
13 Nov 2013CPOL 27.6K   205  
Removes text lines containing specific words/string from files.

Introduction 

A small application addressing one task: remove lines containing specific words from a bunch of files under given folder.

Background  

Once a while I get a task need to clear something from existing text files which are well formatted.

At first I search the keyword using NodePad++ and then double click and delete the lines one by one manually, but soon I find that there are too many lines to remove and doing it manually is boring and  cannot guarantee correctness.

So I begin the code of this small tool written in WPF.

Using the code

To use the tool, follow steps below:

  1. Set the string/words to search.
  2. Set the folder to detect files.
  3. Set the file pattern which can contain wildcards. E.g., *.txt for all Text files; prefix*.txt for all test files naming start with 'prefix'.
  4. Click 'Analyze' button to preview the lines that will be removed.
  5. And then click 'Remove lines' and it will do the job to clean up the files.

Here is code for SearchAndRemoveViewModel

C#
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Windows;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.ViewModel;

namespace LineRemover.ViewModel
{
    class SearchAndRemoveViewModel : NotificationObject, IDataErrorInfo
    {
        private string _searchString;
        private string _searchFolder;
        private string _filePattern;
        private string _status;

        private readonly List<string> _filesToModify = new List<string>();

        public string SearchFolder
        {
            get { return _searchFolder; }
            set
            {
                if (value == _searchFolder) return;
                _searchFolder = value;
                RaisePropertyChanged("SearchFolder");
                RaiseCanExecuteChanged();
            }
        }

        public string SearchString
        {
            get { return _searchString; }
            set
            {
                if (_searchString != value)
                {
                    _searchString = value;
                    RaisePropertyChanged("SearchString");
                    RaiseCanExecuteChanged();
                }
            }
        }

        public string FilePattern
        {
            get { return _filePattern; }
            set
            {
                if (_filePattern != value)
                {
                    _filePattern = value;
                    RaisePropertyChanged("FilePattern");
                }
            }
        }

        public string Status
        {
            get { return _status; }
            set
            {
                if (_status == value) return;
                _status = value;
                RaisePropertyChanged("Status");
            }
        }

        private readonly ObservableCollection<MatchResult> _searchResults = 
                new ObservableCollection<MatchResult>();

        public ObservableCollection<MatchResult> AllResults { get { return _searchResults; } }

        public SearchAndRemoveViewModel()
        {
            SearchString = "Results";
            SearchFolder = @"t:\components";
        }

        private void RaiseCanExecuteChanged()
        {
            AnalyzeCommand.RaiseCanExecuteChanged();
            ApplyCommand.RaiseCanExecuteChanged();
        }

        private DelegateCommand _analyzeCommand;
        public DelegateCommand AnalyzeCommand
        {
            get
            {
                return _analyzeCommand ?? (_analyzeCommand = 
                          new DelegateCommand(Analyze, CanExecuteAnalyze));
            }
        }

        private DelegateCommand _applyCommand;

        public DelegateCommand ApplyCommand
        {
            get { return _applyCommand ?? (_applyCommand = new DelegateCommand(Apply, CanAppy)); }
        }

        private bool CanExecuteAnalyze()
        {
            return this["SearchString"] == null && 
                        this["SearchFolder"] == null;
        }

        private bool CanAppy()
        {
            return this._filesToModify.Any();
        }

        private void Analyze()
        {
            _filesToModify.Clear();

            try
            {
                var allResults = new List<MatchResult>();
                var files = Directory.GetFiles(SearchFolder, FilePattern ?? "*");
                foreach (var file in files)
                {
                    var results = AnalyzeOneFile(file);
                    if (results.Any())
                    {
                        _filesToModify.Add(file);
                        allResults.AddRange(results);
                    }
                }

                AllResults.Clear();
                allResults.ForEach(r=>AllResults.Add(r));
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString(), "Error");
            }

            RaisePropertyChanged("AllResults");

            ApplyCommand.RaiseCanExecuteChanged();
        }

        private void Apply()
        {
            try
            {
                foreach (var file in _filesToModify)
                {
                    Apply(file);
                }

                Status = string.Format("updated {0} files.", _filesToModify.Count);

                _filesToModify.Clear();
                AllResults.Clear();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString(), "Error");
            }
        }

        private void Apply(string file)
        {
            Status = "applying to " + file;

            var lines = File.ReadAllLines(file);
            bool noChange = true;
            var updated = new List<string>();
            foreach (var line in lines)
            {
                if (line != null && line.IndexOf(SearchString, 
                          StringComparison.InvariantCultureIgnoreCase) < 0)
                {
                    updated.Add(line);
                }
                else
                {
                    noChange = false;
                }
            }

            if (!noChange)
            {
                using (var stream = File.OpenWrite(file))
                {
                    using (var writer = new StreamWriter(stream))
                    {
                        writer.BaseStream.Seek(0, SeekOrigin.Begin);
                        writer.BaseStream.SetLength(writer.Encoding.GetPreamble().Length);

                        foreach (var line in updated)
                        {
                            writer.WriteLine(line);
                        }

                        writer.Flush();
                    }
                }
            }

            Status = "applied to " + file;
        }

        private IList<MatchResult> AnalyzeOneFile(string file)
        {
            var results = new List<MatchResult>();

            var lines = File.ReadAllLines(file);
            int lineNo = 0;
            foreach (string line in lines)
            {
                if (line != null && line.IndexOf(SearchString, 
                          StringComparison.InvariantCultureIgnoreCase) >= 0)
                {
                    var result = new MatchResult { LineNo = lineNo, LineContent = line, FileName = file };
                    results.Add(result);
                }
                ++lineNo;
            }

            return results;
        }

        public string this[string columnName]
        {
            get
            {
                if (columnName == "SearchString")
                {
                    if (String.IsNullOrEmpty(SearchString))
                    {
                        return "search string is required.";
                    }
                }

                if (columnName == "SearchFolder")
                {
                    if (String.IsNullOrEmpty(SearchFolder))
                    {
                        return "search folder is required.";
                    }
                }

                return null;
            }
        }

        public string Error { get; private set; }
    }
}

Points of Interest 

As an engineer surely we can figure out ways to automate manual work.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)