How to FINDSTR seek an occurrence within a numeric

2019-04-17 17:19发布

问题:

How do I get "FINDSTR" find a value between a specified range ? I set the "string": "20141001" and "20141030" . If within the *.TXT file exists "20141017", should return the "ERRORLEVEL" = 0.

EXEMPLE:

@echo off

SET DATE_STA=20141001
SET DATE_END=20141030

echo Looking for all the files in the folder
echo within the range from %DATE_STA% to %DATA_END% ...
echo.

:FINDING
findstr /r "%DATE_STA% to %DATA_END%" C:\Folder\*.txt
IF %ERRORLEVEL%==0 (
goto OKAY) else (
goto FAIL
)

:OKAY
cls
echo.
echo Located file that contains a value in the specified range.
echo.
pause
exit

:FAIL
cls
echo.
echo Any file located in this folder..
echo.
pause
exit

回答1:

  • Use findstr with a regexp that catches only the strings you want:

    findstr /r "\<201410[0-3][0-9]\>"
    

    Of course this is a simplified regexp that will also catch 31 of October (which is bad) and the invalid 00 and 39 (but if your file contains only valid dates it's not a problem), so you'll have to write several regexps for each 10 day range.

  • Or generate a list of the dates in a loop, write them to a file and use that file in findstr. Here's an example that generates two date scopes: 20141001 20141030 and 20151001 20151030:

    @echo off
    del "%temp%\datespan.txt" >nul 2>&1
    call :makeDates 20141001 20141030 "%temp%\datespan.txt"
    call :makeDates 20151001 20151030 "%temp%\datespan.txt"
    findstr /g:"%temp%\datespan.txt" /s C:\Folder\*.txt
    del "%temp%\datespan.txt"
    pause
    exit /b
    
    :makeDates
        setlocal enableDelayedExpansion
        set "date1=%1" & set "date2=%2" & set "dateFile=%3"
        set "y1=!date1:~0,4!" & set "m1=1!date1:~4,2!" & set "d1=1!date1:~6,2!"
        set "y2=!date2:~0,4!" & set "m2=1!date2:~4,2!" & set "d2=1!date2:~6,2!"
        set /a m1-=100, d1-=100, m2-=100, d2-=100
        call :dateCalcLeap & call :dateCalcMonth
        :dateNext
            set "m=0!m1!" & set "d=0!d1!" & set "ymd=!y1!!m:~-2!!d:~-2!"
            if !ymd! GTR !date2! endlocal & exit /b
    
            echo !ymd!>>!dateFile!
    
            set /a d1+=1 & if !d1! GTR !mDays! (
                set "d1=1" & set /a m1+=1 & call :dateCalcMonth
                if !m1! GTR 12 set "m1=1" & set /a y1+=1 & call :dateCalcLeap
            )
            goto dateNext
        :dateCalcMonth
            if !m1!==2 (set/a mDays=28+leapYear) else (set/a mDays="31-(m1-1) %% 7 %% 2")
            exit /b
        :dateCalcLeap
            set leapYear=0
            set /a y4=y1 %% 4 & if !y4!==0 (
                set /a y100=y1 %% 100 & if not !y100!==0 set leapYear=1
                set /a y400=y1 %% 400 & if !y400!==0 set leapYear=1
            )
            exit /b
    

    The above solution will [erroneously] catch the numbers inside other bigger numbers like 22222220141001 so if this is undesirable here's a much slower but more reliable version:

    @echo off
    del "%temp%\datespan.txt" >nul 2>&1
    call :makeDates 20141001 20141030 "%temp%\datespan.txt"
    call :makeDates 20151001 20151030 "%temp%\datespan.txt"
    findstr /g:"%temp%\datespan.txt" /s C:\Folder\*.txt
    del "%temp%\datespan.txt"
    pause
    exit /b
    
    :makeDates
        setlocal enableDelayedExpansion
        set "date1=%1" & set "date2=%2" & set "dateFile=%3"
        set "y1=!date1:~0,4!" & set "m1=1!date1:~4,2!" & set "d1=1!date1:~6,2!"
        set "y2=!date2:~0,4!" & set "m2=1!date2:~4,2!" & set "d2=1!date2:~6,2!"
        set /a m1-=100, d1-=100, m2-=100, d2-=100
        call :dateCalcLeap & call :dateCalcMonth
        :dateNext
            set "m=0!m1!" & set "d=0!d1!" & set "ymd=!y1!!m:~-2!!d:~-2!"
            if !ymd! GTR !date2! endlocal & exit /b
    
            echo \^<!ymd!\^>>>!dateFile!
    
            rem The next three lines catch embedded dates like abc20141001, 10_20141001_22
            echo [^^^^0-9]!ymd![^^^^0-9]>>!dateFile!
            echo [^^^^0-9]!ymd!\^>>>!dateFile!
            echo \^<!ymd![^^0-9]>>!dateFile!
    
            set /a d1+=1 & if !d1! GTR !mDays! (
                set "d1=1" & set /a m1+=1 & call :dateCalcMonth
                if !m1! GTR 12 set "m1=1" & set /a y1+=1 & call :dateCalcLeap
            )
            goto dateNext
        :dateCalcMonth
            if !m1!==2 (set/a mDays=28+leapYear) else (set/a mDays="31-(m1-1) %% 7 %% 2")
            exit /b
        :dateCalcLeap
            set leapYear=0
            set /a y4=y1 %% 4 & if !y4!==0 (
                set /a y100=y1 %% 100 & if not !y100!==0 set leapYear=1
                set /a y400=y1 %% 400 & if !y400!==0 set leapYear=1
            )
            exit /b
    


回答2:

I'm not aware of a good FINDSTR solution. But there is a simple solution using JREPL.BAT - a regular expression text processing utility that runs natively on any Windows machine from XP onward. It is pure script (hybrid batch/JScript) that does not require any 3rd party executables.

The solution uses a simple regular expression, coupled with a tiny bit of custom JScript code provided on the command line.

for /r %%F in (.) do @type "%%F\*.txt" 2>nul | jrepl "\d{8,}" "($0>=20141001 && $0<=20141030) ? $0 : false" /jmatch >nul && echo FOUND || echo NOT FOUND