C#在多行字符串中查找指定信息,类似linux下的grep功能
using System; using System.IO; using System.Runtime.InteropServices; using System.Text.RegularExpressions; namespace RobvanderWoude { class RxGrep { public static int skipmatches = 0; public static int takematches = 0; static int Main( string[] args ) { try { #region Command Line Parsing // Check for /? on the command line foreach ( string arg in args ) { if ( arg == "/?" ) { return WriteError( ); } } string filename = string.Empty; string pattern = string.Empty; string[] options = null; RegexOptions regexoptions = RegexOptions.None; bool isredirected = ConsoleEx.InputRedirected; int redirectnum = ( isredirected ? 1 : 0 ); string input = string.Empty; // Check and interpret command line arguments switch ( args.Length + redirectnum ) { case 2: if ( isredirected ) { pattern = args[0]; } else { filename = args[0]; pattern = args[1]; } break; case 3: case 4: case 5: if ( isredirected ) { pattern = args[0]; options = args.Slice( 1, args.Length ); } else { filename = args[0]; pattern = args[1]; options = args.Slice( 2, args.Length ); } break; default: return WriteError( ); } if ( options != null ) { foreach ( string option in options ) { // Right now, /I is the only valid command line switch switch ( option.ToUpper( ).Substring( 0, 2 ) ) { case "/I": regexoptions |= RegexOptions.IgnoreCase; break; case "/S": try { skipmatches = Convert.ToInt32( option.Substring( 3 ) ); } catch ( Exception e ) { Console.Error.WriteLine( "Error: {0}", e.Message ); return WriteError( "Invalid command line switch: " + option ); } break; case "/T": try { takematches = Convert.ToInt32( option.Substring( 3 ) ); } catch ( Exception e ) { Console.Error.WriteLine( "Error: {0}", e.Message ); return WriteError( "Invalid command line switch: " + option ); } break; default: return WriteError( "Invalid command line " + ( option.Substring( 0, 1 ) == "/" ? "switch" : "argument" ) + ": " + option ); } } } if ( isredirected ) { // Read the redirected Standard Input input = Console.In.ReadToEnd( ); } else { // Check if the file name is valid if ( filename.IndexOf( "/" ) > -1 ) { return WriteError( ); } if ( filename.IndexOfAny( "?*".ToCharArray( ) ) > -1 ) { return WriteError( "Wildcards not allowed" ); } // Check if the file exists if ( File.Exists( filename ) ) { // Read the file content using ( StreamReader file = new StreamReader( filename ) ) { input = file.ReadToEnd( ); } } else { return WriteError( "File not found: \"" + filename + "\"" ); } } #endregion Command Line Parsing // Now that the command line parsing is done, let's get some action if ( DisplayMatches( input, pattern, regexoptions ) == 0 ) { return WriteError( "No match found" ); } else { return 0; } } catch ( Exception e ) { return WriteError( e.Message ); } } // The main functionality: display all matching substrings public static int DisplayMatches( string haystack, string needle, RegexOptions options ) { int counter = 0; int displayed = 0; // Get all matches MatchCollection matches = Regex.Matches( haystack, needle, options ); if ( matches.Count > skipmatches ) { foreach ( Match match in matches ) { if ( counter >= skipmatches && ( displayed < takematches || takematches == 0 ) ) { Console.WriteLine( match.Value ); displayed += 1; } counter += 1; } } return displayed; } #region Redirection Detection // Code to detect redirection by Hans Passant on StackOverflow.com // http://stackoverflow.com/questions/3453220/how-to-detect-if-console-in-stdin-has-been-redirected public static class ConsoleEx { public static bool OutputRedirected { get { return FileType.Char != GetFileType( GetStdHandle( StdHandle.Stdout ) ); } } public static bool InputRedirected { get { return FileType.Char != GetFileType( GetStdHandle( StdHandle.Stdin ) ); } } public static bool ErrorRedirected { get { return FileType.Char != GetFileType( GetStdHandle( StdHandle.Stderr ) ); } } // P/Invoke: private enum FileType { Unknown, Disk, Char, Pipe }; private enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 }; [DllImport( "kernel32.dll" )] private static extern FileType GetFileType( IntPtr hdl ); [DllImport( "kernel32.dll" )] private static extern IntPtr GetStdHandle( StdHandle std ); } #endregion Redirection Detection #region Error Handling public static int WriteError( Exception e = null ) { return WriteError( e == null ? null : e.Message ); } public static int WriteError( string errorMessage ) { Console.OpenStandardError( ); if ( string.IsNullOrEmpty( errorMessage ) == false ) { Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.Red; Console.Error.Write( "ERROR: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( errorMessage ); Console.ResetColor( ); } /* RxGrep, Version 2.00 Multi-line FindStr/Grep like tool Usage: RXGREP filename pattern [ /I ] [ /S:nn ] [ /T:nn ] or: some_command | RXGREP pattern [ /I ] [ /S:nn ] [ /T:nn ] Where: filename is the file to be filtered some_command is the command whose standard output is to be filtered pattern is the search pattern (regular expression) /I makes the search case insensitive /S:nn Skip the first nn matches /T:nn Take only nn matches Example: ROBOCOPY D:\sourcedir E:\targetdir /NP /MIR | RXGREP "\s+\d+\s+D:\\sourcedir\\[^\n\r]*\r\n([^\n\r\\]+\r\n)+" (to be read as a single command line) will return something like: 125 D:\sourcedir\subdir\ New File 342 brandnewfile.ext Newer 4.06m updatedfile.ext *EXTRA File 2.40m deletedfile.ext Check for redirection by Hans Passant on StackOverflow.com /questions/3453220/how-to-detect-if-console-in-stdin-has-been-redirected Array Slice extension by Sam Allen http://www.dotnetperls.com/array-slice Written by Rob van der Woude http://www.robvanderwoude.com */ Console.Error.WriteLine( ); Console.Error.WriteLine( "RxGrep, Version 2.00" ); Console.Error.WriteLine( "Multi-line FindStr/Grep like tool" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "RXGREP filename pattern [ /I ] [ /S:nn ] [ /T:nn ]" ); Console.ResetColor( ); Console.Error.Write( "or: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "some_command | RXGREP pattern [ /I ] [ /S:nn ] [ /T:nn ]" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "filename" ); Console.ResetColor( ); Console.Error.WriteLine( " is the file to be filtered" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " some_command" ); Console.ResetColor( ); Console.Error.WriteLine( " is the command whose standard output is to be filtered" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " pattern" ); Console.ResetColor( ); Console.Error.WriteLine( " is the search pattern (regular expression)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /I" ); Console.ResetColor( ); Console.Error.Write( " makes the search case " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "I" ); Console.ResetColor( ); Console.Error.WriteLine( "nsensitive" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /S:nn S" ); Console.ResetColor( ); Console.Error.Write( "kip the first " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "nn" ); Console.ResetColor( ); Console.Error.WriteLine( " matches" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /T:nn T" ); Console.ResetColor( ); Console.Error.Write( "ake only " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "nn" ); Console.ResetColor( ); Console.Error.WriteLine( " matches" ); Console.Error.WriteLine( ); Console.Error.Write( "Example: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( @"ROBOCOPY D:\sourcedir E:\targetdir /NP /MIR |" ); Console.Error.WriteLine( @" RXGREP ""\s+\d+\s+D:\\sourcedir\\[^\n\r]*\r\n([^\n\r\\]+\r\n)+""" ); Console.ResetColor( ); Console.Error.WriteLine( " (to be read as a single command line) will return something like:" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( @" 125 D:\sourcedir\subdir\" ); Console.Error.WriteLine( " New File 342 brandnewfile.ext" ); Console.Error.WriteLine( " Newer 4.06m updatedfile.ext" ); Console.Error.WriteLine( " *EXTRA File 2.40m deletedfile.ext" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Check for redirection by Hans Passant on " ); Console.ForegroundColor = ConsoleColor.DarkGray; Console.Error.WriteLine( "StackOverflow.com" ); Console.Error.WriteLine( "/questions/3453220/how-to-detect-if-console-in-stdin-has-been-redirected" ); Console.ResetColor( ); Console.Error.Write( "Array Slice extension by Sam Allen " ); Console.ForegroundColor = ConsoleColor.DarkGray; Console.Error.WriteLine( "http://www.dotnetperls.com/array-slice" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Written by Rob van der Woude" ); Console.Error.Write( "http://www.robvanderwoude.com" ); Console.OpenStandardOutput( ); return 1; } #endregion Error Handling } #region Extensions // Array Slice // http://www.dotnetperls.com/array-slice public static class Extensions { /// <summary> /// Get the array slice between the two indexes. /// ... Inclusive for start index, exclusive for end index. /// </summary> public static T[] Slice<T>( this T[] source, int start, int end ) { // Handles negative ends. if ( end < 0 ) { end = source.Length + end; } int len = end - start; // Return new array. T[] res = new T[len]; for ( int i = 0; i < len; i++ ) { res[i] = source[i + start]; } return res; } } #endregion Extensions }
附件:源代码下载