Last things first: I don't consider this challenge ruined by the possiblity of
using findstr to grep for lines in a file, because
(a) the challenge is not about just solving a real world problem (for that
it would certainly be the 'best' solution to use some ready made tool
(e.g. grep)), but about doing something interesting (I hope) in VBScript
(b) AFAIK, you can't ask findstr for context (lines before/after)
Currently, I use this script:
'' sqa.vbs - software quality assurance script for project "grep challange"
' #############################################################################
Option Explicit
Dim goFS : Set goFS = CreateObject( "Scripting.FileSystemObject" )
Dim goWSH : Set goWSH = CreateObject( "WScript.Shell" )
WScript.Quit doMain()
Function doMain()
Dim sFSpec
For Each sFSpec In Array( ".\linesincontext.txt" )
Dim sPat
For Each sPat In Array( "[1458]" )
Dim aLBA
For Each aLBA In Array( Array( 0, 0 ), Array( 1, 1 ) )
Dim sExp : sExp = useGrep( sFSpec, sPat, aLBA( 0 ), aLBA( 1 ) )
WScript.Echo "======================"
WScript.Echo sExp
Dim sFnc
For Each sFnc In Array( "useFindstr", "useEhvbs", "useEBGreen", "useSafm" )
Dim sRes : sRes = GetRef( sFnc )( sFSpec, sPat, aLBA( 0 ), aLBA( 1 ) )
WScript.Echo sFnc, "works like grep:", CStr( sExp = sRes )
WScript.Echo sRes
WScript.Echo "----------------------"
Next
Next
Next
Next
doMain = 0
End Function
Function useGrep( sFSpec, sPat, nLB, nLA )
Dim sCmd : sCmd = "f:\cygwin\bin\grep.exe -B" & nLB & " -A" & nLA & " " & sPat & " " & sFSpec
WScript.Echo sCmd
useGrep = goWSH.Exec( sCmd ).Stdout.ReadAll()
End Function
Function useFindStr( sFSpec, sPat, nLB, nLA )
Dim sCmd : sCmd = "findstr /R /C:" & sPat & " " & sFSpec
WScript.Echo sCmd
useFindStr = goWSH.Exec( sCmd ).Stdout.ReadAll()
End Function
Function useEhVbs( sFSpec, sPat, nLB, nLA )
Dim sCmd : sCmd = "cscript ehvbs02.vbs /B:" & nLB & " /A:" & nLA & " " & sPat & " " & sFSpec
WScript.Echo sCmd
useEhVbs = goWSH.Exec( sCmd ).Stdout.ReadAll()
End Function
Function useEBGreen( sFSpec, sPat, nLB, nLA )
Dim sCmd : sCmd = "cscript ebgreen02.vbs /B:" & nLB & " /A:" & nLA & " " & sPat & " " & sFSpec
WScript.Echo sCmd
useEBGreen = goWSH.Exec( sCmd ).Stdout.ReadAll()
End Function
Function useSafm( sFSpec, sPat, nLB, nLA )
Dim sCmd : sCmd = "cscript safm02.vbs /B:" & nLB & " /A:" & nLA & " " & sPat & " " & sFSpec
WScript.Echo sCmd
useSafm = goWSH.Exec( sCmd ).Stdout.ReadAll()
End Function
to test different programs. From the output:
f:\cygwin\bin\grep.exe -B0 -A0 [1458] .\linesincontext.txt
======================
Line 1
Line 4
Line 5
Line 8
findstr /R /C:[1458] .\linesincontext.txt
useFindstr works like grep: Wahr
Line 1
Line 4
Line 5
Line 8
----------------------
cscript ehvbs02.vbs /B:0 /A:0 [1458] .\linesincontext.txt
useEhvbs works like grep: Wahr
Line 1
Line 4
Line 5
Line 8
----------------------
cscript ebgreen02.vbs /B:0 /A:0 [1458] .\linesincontext.txt
useEBGreen works like grep: Wahr
Line 1
Line 4
Line 5
Line 8
----------------------
cscript safm02.vbs /B:0 /A:0 [1458] .\linesincontext.txt
useSafm works like grep: Wahr
Line 1
Line 4
Line 5
Line 8
----------------------
f:\cygwin\bin\grep.exe -B1 -A1 [1458] .\linesincontext.txt
======================
Line 0
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
findstr /R /C:[1458] .\linesincontext.txt
useFindstr works like grep: Falsch
Line 1
Line 4
Line 5
Line 8
----------------------
cscript ehvbs02.vbs /B:1 /A:1 [1458] .\linesincontext.txt
useEhvbs works like grep: Wahr
Line 0
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
----------------------
cscript ebgreen02.vbs /B:1 /A:1 [1458] .\linesincontext.txt
useEBGreen works like grep: Falsch
Line 0
Line 1
Line 2
Line 3
Line 4
Line 5
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
----------------------
cscript safm02.vbs /B:1 /A:1 [1458] .\linesincontext.txt
useSafm works like grep: Falsch
Line 1
Line 3
Line 4
Line 4
Line 4
Line 5
Line 5
Line 7
Line 8
Line 8
----------------------
I conclude, that the contest is still open.
I got the idea for this challenge while reading about (ring) buffers. So I
was surprised that both scripts used an extra array. To get a feling for this
approach, I wrote this program (ehvbs02.vbs):
'' ehvbs02.vbs - grep challenge: Scan a file for a regex and display matches,
'' lines before and lines after
' #############################################################################
Option Explicit
Dim goFS : Set goFS = CreateObject( "Scripting.FileSystemObject" )
WScript.Quit doMain()
Function doMain()
Dim dicArgs : Set dicArgs = parseArgs()
Dim oRE : Set oRE = New RegExp
oRE.Pattern = dicArgs( 0 )
Dim aLines : aLines = Split( goFS.OpenTextFile( dicArgs( 1 ) ).ReadAll(), vbCrLf )
ReDim aShow( UBound( aLines ) )
Dim nIdxF
For nIdxF = 0 To UBound( aLines )
If oRE.Test( aLines( nIdxF ) ) Then
Dim nIdxB : nIdxB = Max( nIdxF - dicArgs( "B" ), LBound( aLines ) )
Dim nIdxA : nIdxA = Min( nIdxF + dicArgs( "A" ), UBound( aLines ) )
Dim nIdxS
For nIdxS = nIdxB To nIdxA
aShow( nIdxS ) = True
Next
End If
Next
For nIdxF = 0 To UBound( aLines )
If aShow( nIdxF ) Then WScript.Echo aLines( nIdxF )
Next
doMain = 0
End Function
Function Max( a, b )
If a > b Then Max = a Else Max = b End If
End Function
Function Min( a, b )
If a < b Then Min = a Else Min = b End If
End Function
Function parseArgs()
Dim dicRVal : Set dicRVal = CreateObject( "Scripting.Dictionary" )
Dim vItem
For Each vItem In WScript.Arguments.Named
dicRVal( vItem ) = WScript.Arguments.Named( vItem )
Next
Dim nCnt : nCnt = 0
For Each vItem In WScript.Arguments.UnNamed
dicRVal( nCnt ) = vItem
nCnt = nCnt + 1
Next
Set parseArgs = dicRVal
End Function
Thank you, dm_4ever, TNO, suchafunkymonkey, and ebgreen, for your interest and
effort spend on this challenge.