Click here to Skip to main content
Click here to Skip to main content
Go to top

A C# Grep Application

, 11 Mar 2003
Rate this:
Please Sign up or sign in to vote.
Presenting a small C# application which provides Grep-like functionality under .NET.

This article was updated based on suggestions received from readers.

Traditionally grep stands for "Global Regular Expression Print". Global means that an entire file is searched. Regular Expression means that a regular expression string is used to establish a search pattern. Print means that the findings will be displayed. Simply put, grep searches an entire file for the pattern you want and displays its findings.

Now two variants of the C# Grep Application are provided: the Windows Form variant and the Console variant.

 Sample Image - WinGrep.jpg

The Windows Form variant was improved by adding new search options, providing the capability for regular expression searching and implementing the search process in a separate thread. The application can be used for searching in given types of text files for a given regular expression. The following user options can be selected:

  • Count Lines - to print a count of matching lines for each input file;
  • Ignore Case - to ignore case in pattern (search expression);
  • Just Files - to print just file names (scanning will stop on first match in a file);
  • Line Numbers - to prefix each line of output with line number;
  • Recursive - for recursive search in subdirectories;

The results are printed in a multiline Edit BOx according to the selected options. The search results can be copied from the Edit Box to the Clipboard by right clicking on the Edit Box and selecting Copy from the context menu. The files are searched inside a given directory, or recursively from its subdirectories, if the Recursive option is selected. In order to specify the search directory and the file extension you can edit manually, or you can select a file from an open file dialog box and the directory and file extension will be added automatically. You can specify more than one file extension or pattern by separating them with comma.

Sample Image - ConsGrep.jpg

The Console variant is using a syntax different from the traditional Unix syntax, I prefered a syntax similar to csc, the C# compiler.

grep [/h|/H]
grep [/c] [/i] [/l] [/n] [/r] /E:reg_exp /F:files

The command line options are similar to the ones for the Windows Form variant:

  • /h|/H - printing a usage help explanatory text;
  • /c - print a count of matching lines for each input file;
  • /i - ignore case in pattern;
  • /l - print just files (scanning will stop on first match);
  • /n - prefix each line of output with line number;
  • /r - recursive search in subdirectories;
  • /E:reg_exp - the Regular Expression used as search pattern. The Regular Expression can be delimited by quotes like "..." and '...' if you want to include in it leading or trailing blanks;
  • /F:files - the list of input files. The files can be separated by commas as in /F:file1,file2,file3 and wildcards can be used for their specification as in /F:*file?.txt;

Example:

grep /c /n /r /E:" C Sharp " /F:*.cs

For parsing the command line arguments I used a slightly modified version of the Arguments class presented by author GriffonRL in the article with Code Project C#/.NET Command Line Arguments Parser. The modification was just to replace the use of StringDictionary container with HybridDictionary container in order to allow case sensitive keys. Full credits are given to the original author in the source code.

The fully operational Visual Studio.NET projects are provided in .zip files attached to the article. I have put some comments in the code, but generally it is self explanatory.

I was really amazed about how easy it was to develop these applications in C# and how short are the final source files compared to the case if I would have chosen another programming language and technology. I hope that this example will serve as a stimulus for other people to learn C# and the .NET techology!

I am interested in any opinions and new ideas about this implementation!

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

Share

About the Author

George Anescu
Web Developer
Romania Romania
No Biography provided

Comments and Discussions

 
QuestionVS2010 version? PinmemberTatworth5-Feb-12 9:44 
AnswerRe: VS2010 version? [modified] PinmemberTatworth9-Feb-12 22:09 
Questiontext serach withing a zip file Pinmemberswapsshah@gmail.com9-Oct-07 20:31 
AnswerRe: text serach withing a zip file PinmemberSingh Vikas10-Oct-07 11:50 
GeneralSpeed it up and handle exceptions better PinmemberRed Flying Pig28-Sep-06 3:56 
GeneralRe: Speed it up and handle exceptions better Pinmembersides_dale14-Apr-07 16:24 
GeneralConGrep Output Pinmemberdetial6110-Nov-05 22:41 
GeneralSystem.UnauthorizedAccessException Pinmembercoder@coder.gr8-May-05 10:10 
GeneralRe: System.UnauthorizedAccessException PinmemberEric Engler20-May-05 9:40 
GeneralAnd to think I nearly bought one of these... Pinmemberlurkbat16-Jul-04 0:08 
GeneralGrep Class implementation PinmemberJMBezeau18-May-04 10:33 
QuestionRe: Grep Class implementation Pinmemberswapsshah@gmail.com8-Oct-07 20:09 
AnswerRe: Grep Class implementation PinmemberJMBezeau9-Oct-07 2:02 
GeneralRe: Grep Class implementation PinmemberJMBezeau22-Sep-10 7:07 
Here is the source code for my class. I have done this a long time ago, I am no longer familiar with the code.
 

Imports System
Imports System.Collections
Imports System.Text.RegularExpressions
Imports System.IO
Imports System.Security
 

'Traditionally grep stands for "Global Regular Expression Print".
'Global means that an entire file is searched.
'Regular Expression means that a regular expression string is used to establish a search pattern.
'Print means that the command will display its findings.
'Simply put, grep searches an entire file for the pattern you want and displays its findings.
'
'The use syntax is different from the traditional Unix syntax, I prefer a syntax similar to
'csc, the C# compiler.
'
' grep [/h|/H] - Usage Help
'
' grep [/c] [/i] [/l] [/n] [/r] [/p] /E:reg_exp /F:files
'
' /c - print a count of matching lines for each input file;
' /i - ignore case in pattern;
' /l - print just files (scanning will stop on first match);
' /n - prefix each line of output with line number;
' /r - recursive search in subdirectories;
' /p - consider expression as a string literal
'
' /E:reg_exp - the Regular Expression used as search pattern. The Regular Expression can be delimited by
' quotes like "..." and '...' if you want to include in it leading or trailing blanks;
'
' /F:files - the list of input files. The files can be separated by commas as in /F:file1,file2,file3
'and wildcards can be used for their specification as in /F:*file?.txt;
'
'Example:
'
' grep /c /n /r /E:" C Sharp " /F:*.cs
 
Namespace grep
 

''' <summary>
''' Wrapper class around the grep sample code from CodeProject.
''' </summary>
Public Class grep
'Option Flags
Private m_bRecursive As Boolean
Private m_bIgnoreCase As Boolean
Private m_bJustFiles As Boolean
Private m_bLineNumbers As Boolean
Private m_bCountLines As Boolean
Private m_bPlaintext As Boolean
Private m_strRegEx As String
Private m_vRegEx() As String
Private m_strFiles As String
Private m_strDir As String
 
'ArrayList keeping the Files
Private m_arrFiles As New ArrayList
 
' Result information
'private ArrayList m_arrResultFiles = new ArrayList();
'private ArrayList m_arrResultLineNumbers = new ArrayList();
Public Event Display(ByVal strMessage As String)
Public Event FilesFound(ByVal iNumber As Integer)
Public Event DisplayHit(ByVal strFileName As String, ByVal iNbHit As Integer, ByVal strTrouve As String, ByVal strLigne As String)
 

Public Sub New()
End Sub 'New
 
'Properties
 
Public Property Recursive() As Boolean
Get
Return m_bRecursive
End Get
Set(ByVal Value As Boolean)
m_bRecursive = Value
End Set
End Property
 
Public Property IgnoreCase() As Boolean
Get
Return m_bIgnoreCase
End Get
Set(ByVal Value As Boolean)
m_bIgnoreCase = Value
End Set
End Property
 
Public Property JustFiles() As Boolean
Get
Return m_bJustFiles
End Get
Set(ByVal Value As Boolean)
m_bJustFiles = Value
End Set
End Property
 
Public Property LineNumbers() As Boolean
Get
Return m_bLineNumbers
End Get
Set(ByVal Value As Boolean)
m_bLineNumbers = Value
End Set
End Property
 
Public Property CountLines() As Boolean
Get
Return m_bCountLines
End Get
Set(ByVal Value As Boolean)
m_bCountLines = Value
End Set
End Property
 
Public Property Plaintext() As Boolean
Get
Return m_bPlaintext
End Get
Set(ByVal Value As Boolean)
m_bPlaintext = Value
End Set
End Property
 
Public Property Expression() As String
Get
Return m_strRegEx
End Get
Set(ByVal Value As String)
m_vRegEx = Nothing
m_strRegEx = Value
End Set
End Property
 
Public Property Expressions() As String()
Get
Return m_vRegEx
End Get
Set(ByVal Value As String())
m_strRegEx = Nothing
m_vRegEx = Value
End Set
End Property
 
Public Property Files() As String
Get
Return m_strFiles
End Get
Set(ByVal Value As String)
m_strFiles = Value
End Set
End Property
 
Public Property Dir() As String
Get
Return m_strDir
End Get
Set(ByVal Value As String)
m_strDir = Value
End Set
End Property
 
'Build the list of Files
Private Sub GetFiles(ByVal strDir As [String], ByVal strExt As [String], ByVal bRecursive As Boolean)
'search pattern can include the wild characters '*' and '?'
Dim fileList As String() = Directory.GetFiles(strDir, strExt)
For i As Integer = 0 To fileList.Length - 1
If File.Exists(fileList(i)) Then
m_arrFiles.Add(fileList(i))
End If
Next i
If bRecursive = True Then
'Get recursively from subdirectories
Dim dirList As String() = Directory.GetDirectories(strDir)
For i As Integer = 0 To dirList.Length - 1
GetFiles(dirList(i), strExt, True)
Next i
End If
End Sub 'GetFiles
 

'Search Function
Public Sub Search()
Dim strDir As [String] = m_strDir
'First empty the list
m_arrFiles.Clear()
'Create recursively a list with all the files complying with the criteria
Dim astrFiles As [String]() = m_strFiles.Split(New [Char]() {","c})
 
For i As Integer = 0 To astrFiles.Length - 1
'Eliminate white spaces
astrFiles(i) = astrFiles(i).Trim()
GetFiles(strDir, astrFiles(i), m_bRecursive)
Next i
'Now all the Files are in the ArrayList, open each one
'iteratively and look for the search string
Dim strResults As [String] = "Grep Results:" + ControlChars.Cr + ControlChars.Lf + ControlChars.Cr + ControlChars.Lf
Dim strLine As [String]
Dim exExpression As Regex
 
If m_vRegEx Is Nothing Then
If m_bIgnoreCase = True Then
exExpression = New Regex(m_strRegEx, RegexOptions.IgnoreCase)
Else
exExpression = New Regex(m_strRegEx)
End If
End If
 
Dim iLine, iCount As Integer
Dim bEmpty As Boolean = True
Dim enm As IEnumerator = m_arrFiles.GetEnumerator()
 
RaiseEvent FilesFound(m_arrFiles.Count)
 
While enm.MoveNext()
Try
Dim fi As New FileInfo(CStr(enm.Current))
Dim sr As New StreamReader(fi.OpenRead(), System.Text.Encoding.Default)
 
RaiseEvent DisplayHit(fi.Name, 0, Nothing, Nothing)
 
iLine = 0
iCount = 0
Dim bFirst As Boolean = True
strLine = sr.ReadLine()
While Not (strLine Is Nothing)
Dim mtch As Boolean
Dim found As String
iLine += 1
If m_vRegEx Is Nothing Then
If m_bPlaintext Then
mtch = strLine.IndexOf(m_strRegEx) >= 0
Else
'Using Regular Expressions as a real Grep
mtch = exExpression.Match(strLine).Success
End If
found = m_strRegEx
Else
For Each expr As String In m_vRegEx
If m_bPlaintext Then
mtch = strLine.IndexOf(expr) >= 0
 
Else
If m_bIgnoreCase = True Then
mtch = Regex.Match(strLine, expr, RegexOptions.IgnoreCase).Success
Else
mtch = Regex.Match(strLine, expr).Success
End If
End If
If mtch Then
found = expr
Exit For
End If
Next
End If
'If m_bIgnoreCase = True Then
' mtch = Regex.Match(strLine, m_strRegEx, RegexOptions.IgnoreCase)
'Else
' mtch = Regex.Match(strLine, m_strRegEx)
'End If
If mtch Then
RaiseEvent DisplayHit(fi.Name, iCount, found, strLine)
bEmpty = False
iCount += 1
If bFirst = True Then
If m_bJustFiles = True Then
strResults += CStr(enm.Current) + ControlChars.Cr + ControlChars.Lf
Exit While
Else
strResults += CStr(enm.Current) + ":" + ControlChars.Cr + ControlChars.Lf
End If
bFirst = False
End If
'Add the Line to Results string
If m_bLineNumbers = True Then
strResults &= " " & iLine & ": " & strLine & ControlChars.Cr & ControlChars.Lf
Else
strResults += " " + strLine + ControlChars.Cr + ControlChars.Lf
End If
End If
strLine = sr.ReadLine()
End While
sr.Close()
If bFirst = False Then
If m_bCountLines = True Then
strResults &= " " & iCount & " Lines Matched" & ControlChars.Cr & ControlChars.Lf
End If
strResults &= ControlChars.Cr & ControlChars.Lf
End If
Catch ex As Exception
DisplayMessage("Erreur: " & ex.Message)
End Try
End While
If bEmpty = True Then
DisplayMessage("No matches found!")
Else
DisplayMessage(strResults)
End If
End Sub 'Search
 
Protected Sub DisplayMessage(ByVal strMessage As String)
RaiseEvent Display(strMessage)
End Sub 'DisplayMessage
End Class 'grep
End Namespace 'grep

--
Jean-Michel Bezeau
Computer Science Analyst

GeneralPlz Help me some one..... PinmemberLavinreet Singh16-May-04 19:04 
GeneralThanks for the reference. PinmemberGriffonRL20-Jul-03 22:31 
GeneralA bug and a suggestion Pinmembermatt31019-Mar-03 6:04 
Generalngrep PinmemberBlake Coverett13-Mar-03 11:28 
QuestionCommand line version? PinmemberJon Rista7-Jan-03 16:26 
GeneralCompile question PinmemberMichael Mojica18-Aug-02 15:14 
GeneralRe: Compile question PinmemberGeorge Anescu28-Dec-02 11:13 
QuestionRegular Expressions? PinmemberUwe Keim23-Oct-01 21:01 
AnswerRe: Regular Expressions? PinmemberGeorge Anescu28-Dec-02 11:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 12 Mar 2003
Article Copyright 2001 by George Anescu
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid