using System;
using System.Collections.Generic;
using System.Text;
using EnvDTE80;
using System.Text.RegularExpressions;
using System.IO;
using System.Collections.Specialized;
using System.Collections;
using EnvDTE;
using System.Windows.Forms;
namespace RegexFindAndReplace
{
class StaticFinderAndReplacer
{
private bool _isReplaceNext = false;
private FinderAndReplacer finderAndReplacer = null;
private DTE2 applicationObject;
private int fileCount;
public StaticFinderAndReplacer( DTE2 applicationObject )
{
this.applicationObject = applicationObject;
}
private string pattern = string.Empty;
public string Pattern
{
get
{
return this.pattern;
}
set
{
try
{
Regex testPatternRegex = new Regex( value );
}
catch ( ArgumentException ex )
{
MessageBox.Show( ex.Message );
throw;
}
this.pattern = value;
}
}
private RegexOptions regexOptions = RegexOptions.None;
public RegexOptions RegexOptions
{
set
{
this.regexOptions = value;
}
get
{
return this.regexOptions;
}
}
private string searchDirectory;
public string SearchDirectory
{
get
{
return this.searchDirectory;
}
set
{
this.searchDirectory = value;
}
}
private int matchContextLineCount;
public int MatchContextLineCount
{
get
{
return matchContextLineCount;
}
set
{
matchContextLineCount = value;
}
}
public bool IsReplaceNext
{
set
{
_isReplaceNext = value;
}
}
private StringCollection _replacedFileList = new StringCollection();
private OutputWindowPane outputWindowPane = null;
private ArrayList _matchInfoList = new ArrayList();
public ArrayList MatchInfoList
{
get
{
return _matchInfoList;
}
}
private string fileTypes = string.Empty;
public string FileTypes
{
set
{
this.fileTypes = value;
}
}
private bool includeSubDirectories;
public bool IncludeSubDirectories
{
set
{
this.includeSubDirectories = value;
}
}
private int _backLines;
public int BackLines
{
set
{
_backLines = value;
}
}
private int _frontLines;
public int FrontLines
{
set
{
_frontLines = value;
}
}
public void FindAll()
{
ValidateOutputWindowPane();
this.outputWindowPane.OutputString( string.Format( @"Find all ""{0}"", {1}""{2}"", ""{3}""{4}", this.Pattern, GetRegexOptionsString(), this.searchDirectory, this.fileTypes, Environment.NewLine ) );
FindAllInFiles( this.searchDirectory );
}
private void FindAllInFiles( string directory )
{
string[] fileTypeArray = this.fileTypes.Split( ';' );
foreach ( string fileType in fileTypeArray )
{
foreach ( string fullFilename in Directory.GetFiles( directory, fileType ) )
{
FindInFile( fullFilename );
}
}
if ( this.includeSubDirectories )
{
foreach ( string fileType in fileTypeArray )
{
foreach ( string directoryName in Directory.GetDirectories( directory, fileType ) )
{
FindAllInFiles( directoryName );
}
}
}
}
private void FindInFile( string filename )
{
string source = string.Empty;
using ( StreamReader streamReader = new StreamReader( filename ) )
{
source = streamReader.ReadToEnd();
fileCount++;
}
Regex regex = new Regex( this.Pattern, this.RegexOptions );
foreach ( Match match in regex.Matches( source ) )
{
int lineNumber = MatchContextUtils.GetLineCount( source, match.Index );
MatchContextInfo matchContextInfo = new MatchContextInfo( filename, lineNumber, 0, match.Value, MatchContextUtils.GetMatchContextString( source, match.Index, match.Index + match.Length, this.matchContextLineCount ) );
int lineCount = MatchContextUtils.GetLineCount( matchContextInfo.MatchContext, matchContextInfo.MatchContext.Length );
string fileNameAndLineNumbers = string.Empty;
if ( lineCount != 1 )
{
fileNameAndLineNumbers = string.Format( " {0}({1}-{2}):\n", filename, ( lineNumber - this.matchContextLineCount ) > 0 ? ( lineNumber - this.matchContextLineCount ) : 0, lineNumber + lineCount - 1 );
}
else
{
fileNameAndLineNumbers = string.Format( " {0}({1}): ", filename, lineNumber );
}
this.outputWindowPane.OutputString( string.Format( "{0}{1}{2}", fileNameAndLineNumbers, matchContextInfo.MatchContext, Environment.NewLine ) );
}
}
public void FindNext()
{
this.finderAndReplacer.Pattern = this.Pattern;
this.finderAndReplacer.RegexOptions = this.RegexOptions;
if ( !finderAndReplacer.FindNextForMultipleFiles() )
{
ReplaceNextInFiles( this.searchDirectory, this.fileTypes, string.Empty, true );
}
}
private void showResults( bool isReplace )
{
ValidateOutputWindowPane();
string title1 = string.Empty;
string title2 = string.Empty;
outputWindowPane.Activate();
if ( isReplace )
{
title1 = "Replace";
title2 = "Replaced";
}
else
{
title1 = "Search";
title2 = "Found";
}
outputWindowPane.OutputString( string.Format( "{0} \"{1}\", in {2}{3}", title1, this.Pattern, this.searchDirectory, Environment.NewLine ) );
StringCollection matchedFiles = new StringCollection();
foreach ( MatchContextInfo matchContextInfo in MatchInfoList )
{
string showInfo = string.Format( "{0}({1}): {2}{3}", matchContextInfo.FullFilename, matchContextInfo.StartLine, MatchContextUtils.HasMultipleLines( matchContextInfo.MatchContext ) ? Environment.NewLine : string.Empty, matchContextInfo.MatchContext );
if ( showInfo.LastIndexOf( '\r' ) == showInfo.Length - 1 || showInfo.LastIndexOf( '\n' ) == showInfo.Length - 1 )
outputWindowPane.OutputString( string.Format( "{0}{1}", showInfo, Environment.NewLine ) );
else
outputWindowPane.OutputString( string.Format( "{0}{1}", showInfo, Environment.NewLine ) );
if ( !matchedFiles.Contains( matchContextInfo.FullFilename ) )
matchedFiles.Add( matchContextInfo.FullFilename );
}
outputWindowPane.OutputString( string.Format( "{0} {1}, matched files {2}, Searching files {3}{4}", title2, MatchInfoList.Count, matchedFiles.Count, fileCount, Environment.NewLine ) );
}
public void ReplaceInFiles( string dirPath, string fileSearchPattern, string replacePattern )
{
string[] fileSearchPatternList = fileSearchPattern.Split( ';' );
foreach ( string fileSearchPatternItem in fileSearchPatternList )
{
foreach ( string fullFilename in Directory.GetFiles( dirPath, fileSearchPatternItem ) )
{
ReplaceInOneFile( fullFilename, replacePattern );
}
if ( includeSubDirectories )
{
foreach ( string dirFullName in Directory.GetDirectories( dirPath ) )
{
ReplaceInFiles( dirFullName, fileSearchPattern, replacePattern );
}
}
}
}
public void ReplaceAll( string replacePattern )
{
_matchInfoList.Clear();
ReplaceInFiles( this.searchDirectory, fileTypes, replacePattern );
showResults( true );
}
private void recordReplacedInfomation( string source, string replacedAllSource, string replacePattern, string fullFilename )
{
string replacingSource = source;
int startPos = 0;
while ( true )
{
Regex rg = new Regex( this.Pattern, this.RegexOptions );
Match match = rg.Match( replacingSource, startPos );
if ( match.Success )
{
string changedSource = rg.Replace( replacingSource, replacePattern, 1, startPos );
startPos = match.Index + match.Length;
int replaceTextStartPos = match.Index;//position in changedSource
int replaceTextEndPos = changedSource.Length - ( replacingSource.Length - startPos );//position in changedSource
string replaceText = changedSource.Substring( replaceTextStartPos, replaceTextEndPos - replaceTextStartPos );
int lineNum = MatchContextUtils.GetLineCount( replacedAllSource, replaceTextStartPos ) + 1;
MatchContextInfo matchContextInfo = new MatchContextInfo( fullFilename, lineNum, 0, replaceText, MatchContextUtils.GetMatchContextString( replacedAllSource, replaceTextStartPos, replaceTextEndPos, this.matchContextLineCount ) );
_matchInfoList.Add( matchContextInfo );
replacingSource = changedSource;
}
else
{
break;
}
}
}
private bool ReplaceInOneFile( string fullFilename, string replacePattern )
{
string source = string.Empty;
using ( StreamReader sr = new StreamReader( fullFilename, System.Text.Encoding.GetEncoding( "GB2312" ) ) )
{
source = sr.ReadToEnd();
}
Regex rg = new Regex( this.Pattern, this.RegexOptions );
int replaceCount;
string replacedAllSource = this.finderAndReplacer.ReplaceAll( source, replacePattern, out replaceCount );
if ( replacedAllSource.Length > 0 )
{
if ( _isReplaceNext )
{
this.applicationObject.ItemOperations.OpenFile( fullFilename, Constants.vsViewKindTextView );
return true;
}
else
{
recordReplacedInfomation( source, replacedAllSource, replacePattern, fullFilename );
using ( StreamWriter sw = new StreamWriter( fullFilename, false, System.Text.Encoding.Default ) )
{
sw.Write( replacedAllSource );
}
}
}
return false;
}
public void ReplaceNext( string replacePattern )
{
if ( false )
{
finderAndReplacer.Pattern = this.Pattern;
finderAndReplacer.RegexOptions = this.RegexOptions;
if ( !finderAndReplacer.ReplaceNextForMultipleFiles( replacePattern ) )
{
ReplaceNextInFiles( this.searchDirectory, fileTypes, replacePattern, true );
}
}
else
{
ReplaceNextInFiles( this.searchDirectory, fileTypes, replacePattern, true );
}
}
public bool ReplaceNextInFiles( string dirPath, string fileSearchPattern, string replacePattern, bool isRoot )
{
string[] fileSearchPatternList = fileSearchPattern.Split( ';' );
foreach ( string fileSearchPatternItem in fileSearchPatternList )
{
foreach ( string fullFilename in Directory.GetFiles( dirPath, fileSearchPatternItem ) )
{
if ( !_replacedFileList.Contains( fullFilename ) )
{
_replacedFileList.Add( fullFilename );
if ( ReplaceInOneFile( fullFilename, replacePattern ) )
{
ValidateFinderAndReplacer();
return true;
}
}
}
}
if ( includeSubDirectories )
{
foreach ( string fileSearchPatternItem in fileSearchPatternList )
{
foreach ( string dirFullName in Directory.GetDirectories( dirPath, fileSearchPatternItem ) )
{
if ( ReplaceNextInFiles( dirFullName, fileSearchPattern, replacePattern, false ) )
return true;
}
}
}
if ( isRoot )
{
//UIHelper.ShowInfo( Strings.UI_PROMPT_FIND_TO_END );
}
return false;
}
private void ValidateFinderAndReplacer()
{
if ( finderAndReplacer == null || !( finderAndReplacer.Pattern == this.pattern && finderAndReplacer.RegexOptions == this.regexOptions ) )
{
InitializeFinderAndReplacer();
}
}
private void InitializeFinderAndReplacer()
{
if ( finderAndReplacer == null )
{
finderAndReplacer = new FinderAndReplacer( this.applicationObject );
}
finderAndReplacer.Pattern = this.pattern;
finderAndReplacer.RegexOptions = this.regexOptions;
}
private void ValidateOutputWindowPane()
{
if ( this.outputWindowPane == null )
{
this.outputWindowPane = this.applicationObject.ToolWindows.OutputWindow.OutputWindowPanes.Add( "Regex Find and Replace" );
}
}
private string GetRegexOptionsString()
{
StringBuilder regexOptionsStringBuilder = new StringBuilder();
if ( ( this.regexOptions & RegexOptions.IgnoreCase ) == RegexOptions.IgnoreCase )
{
regexOptionsStringBuilder.Append( "RegexOptions.IgnoreCase" );
}
if ( ( this.regexOptions & RegexOptions.Multiline ) == RegexOptions.Multiline )
{
if ( regexOptionsStringBuilder.Length > 0 )
{
regexOptionsStringBuilder.Append( " | " );
}
regexOptionsStringBuilder.Append( "RegexOptions.Multiline" );
}
if ( ( this.regexOptions & RegexOptions.Singleline ) == RegexOptions.Singleline )
{
if ( regexOptionsStringBuilder.Length > 0 )
{
regexOptionsStringBuilder.Append( " | " );
}
regexOptionsStringBuilder.Append( "RegexOptions.Singleline" );
}
if ( ( this.regexOptions & RegexOptions.ExplicitCapture ) == RegexOptions.ExplicitCapture )
{
if ( regexOptionsStringBuilder.Length > 0 )
{
regexOptionsStringBuilder.Append( " | " );
}
regexOptionsStringBuilder.Append( "RegexOptions.ExplicitCapture" );
}
if ( ( this.regexOptions & RegexOptions.IgnorePatternWhitespace ) == RegexOptions.IgnorePatternWhitespace )
{
if ( regexOptionsStringBuilder.Length > 0 )
{
regexOptionsStringBuilder.Append( " | " );
}
regexOptionsStringBuilder.Append( "RegexOptions.IgnorePatternWhitespace" );
}
if ( ( this.regexOptions & RegexOptions.ECMAScript ) == RegexOptions.ECMAScript )
{
if ( regexOptionsStringBuilder.Length > 0 )
{
regexOptionsStringBuilder.Append( " | " );
}
regexOptionsStringBuilder.Append( "RegexOptions.ECMAScript" );
}
if ( ( this.regexOptions & RegexOptions.RightToLeft ) == RegexOptions.RightToLeft )
{
if ( regexOptionsStringBuilder.Length > 0 )
{
regexOptionsStringBuilder.Append( " | " );
}
regexOptionsStringBuilder.Append( "RegexOptions.RightToLeft" );
}
if ( ( this.regexOptions & RegexOptions.CultureInvariant ) == RegexOptions.CultureInvariant )
{
if ( regexOptionsStringBuilder.Length > 0 )
{
regexOptionsStringBuilder.Append( " | " );
}
regexOptionsStringBuilder.Append( "RegexOptions.CultureInvariant" );
}
if ( regexOptionsStringBuilder.Length > 0 )
{
regexOptionsStringBuilder.Insert( 0, "\"" );
regexOptionsStringBuilder.Append( "\", " );
}
return regexOptionsStringBuilder.ToString();
}
}
}