Find the last occurrence of a string in a file

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
TTwrs1
Posts: 3
Joined: 03 Dec 2016 09:12

Find the last occurrence of a string in a file

#1 Post by TTwrs1 » 03 Dec 2016 09:29

I have text files of varying lengths similar to the following and need a Win batch solution to find the value of the last occurrence of 'time=', in this example 00:24:53.16 .

Code: Select all

Input #0, mp3, from 'test.mp3':
  Metadata:
    encoder         : Lavf57.51.102
  Duration: 00:23:41.31, start: 0.025057, bitrate: 128 kb/s
    Stream #0:0: Audio: mp3, 44100 Hz, stereo, s16p, 128 kb/s
    Metadata:
      encoder         : Lavc57.60
Output #0, null, to 'pipe:':
  Metadata:
    encoder         : Lavf57.51.102
    Stream #0:0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s
    Metadata:
      encoder         : Lavc57.60.101 pcm_s16le
Stream mapping:
  Stream #0:0 -> #0:0 (mp3 (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
size=N/A time=00:03:29.65 bitrate=N/A speed= 419x   
size=N/A time=00:07:56.65 bitrate=N/A speed= 477x   
size=N/A time=00:12:25.43 bitrate=N/A speed= 497x   
size=N/A time=00:16:56.45 bitrate=N/A speed= 508x   
size=N/A time=00:21:22.56 bitrate=N/A speed= 513x   
size=N/A time=00:24:53.16 bitrate=N/A speed= 515x   
video:0kB audio:25720kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown


All the 'lines' starting with 'size=' except the last one end with <sp><sp><sp><sp><cr>, no <lf>, so they are really part of a single line as far a parse-ability is concerned. The very last 'size=' line has a <cr><lf>.

So, the problem really boils down to extracting the last of several occurrences of a string in a line of unknown length, e.g.:

size=N/A time=00:03:29.65 bitrate=N/A speed= 419x size=N/A time=00:07:56.65 bitrate=N/A speed= 477x size=N/A time=00:12:25.43 bitrate=N/A speed= 497x size=N/A time=00:16:56.45 bitrate=N/A speed= 508x size=N/A time=00:21:22.56 bitrate=N/A speed= 513x size=N/A time=00:24:53.16 bitrate=N/A speed= 515x

In case it makes the solution any easier, the desired 'time=' value will always be the last in the file and will always be the 'largest'. I've tried to replace all <cr> with <lf> (no can do because it terminates the parsing), reverse seeking from the end (findstr doesn't support it), and other ideas without success.

The following batch file almost works, but it finds and processes the first 'time=' value, not the last. It converts the value to seconds, strips the echo-added <cr><lf>, sets an environment variable, and sends the result to a file. All good except it does it on the wrong data...

Code: Select all

@echo off
for /F "tokens=1-7 delims==:. " %%1 in (input.txt) do (if "%%1"=="size" call :findtime %%4 %%5 %%6 %%7)
:findtime
echo:
set /A s=%3 & set /A s=s+%2*60 & set /A s=s+%1*60*60
echo:%1:%2:%3.%4 = %s%.%4 seconds
set dur=%s%.%4
echo:%dur% = includes a CRLF
<nul (set/p z=%dur%)
echo: = stripped CRLF, method1
(echo:|set /p ="%dur%")>duration.txt   %= strip CRLF then send to file for later use =%
type duration.txt
echo: = stripped CRLF, method2
echo:
pause


Edit: fixed the 'type duration.txt' line
Last edited by aGerman on 03 Dec 2016 14:55, edited 1 time in total.
Reason: BBCode enabled in order to see line indentations

pieh-ejdsch
Posts: 240
Joined: 04 Mar 2014 11:14
Location: germany

Re: Find the last occurrence of a string in a file

#2 Post by pieh-ejdsch » 04 Dec 2016 07:03

testfileA --> Your file

Code: Select all

@echo off
setlocal
set "F=testfileA"
for /l %%a in (0 1 1) do find "=%%a" <"%F%" >nul && (
  Title %%a
  for /l %%b in (0 1 2) do find "=%%a%%b:" <"%F%" >nul && (
    title =%%a%%b
    for /l %%c in (0 1 5) do find "=%%a%%b:%%c" <"%F%" >nul && (
      title =%%a%%b:%%c
      for /l %%d in (0 1 9) do find "=%%a%%b:%%c%%d:" <"%F%" >nul && (
        title =%%a%%b:%%c%%d:
        for /l %%e in (0 1 5) do find "=%%a%%b:%%c%%d:%%e" <"%F%" >nul && (
          title =%%a%%b:%%c%%d:%%e
          for /l %%f in (0 1 9) do find "=%%a%%b:%%c%%d:%%e%%f." <"%F%" >nul && (
            title =%%a%%b:%%c%%d:%%e%%f.
            for /l %%g in (0 1 9) do find "=%%a%%b:%%c%%d:%%e%%f.%%g" <"%F%" >nul && (
              title =%%a%%b:%%c%%d:%%e%%f.%%g
              for /l %%h in (0 1 9) do find "=%%a%%b:%%c%%d:%%e%%f.%%g%%h " <"%F%" >nul && (
                title =%%a%%b:%%c%%d:%%e%%f.%%g%%h
                echo Time =%%a%%b:%%c%%d:%%e%%f.%%g%%h
                set "lastNR=%%a%%b:%%c%%d:%%e%%f.%%g%%h"
              )
            )
          )
        )
      )
    )
  )
)
echo LastTime =%lastNR%
pause


Phil

TTwrs1
Posts: 3
Joined: 03 Dec 2016 09:12

Re: Find the last occurrence of a string in a file

#3 Post by TTwrs1 » 04 Dec 2016 12:17

Please note that the <sp><sp><sp><sp><cr> was replaced with <cr><lf> somewhere along the line when the input.txt file contents were copied/pasted/posted.

Phil, your script indeed does find the last line in the pasted file. It also works on the 'correct' file. However, when I tried it on another file from a 2-hour mp3 it took over 8-minutes to reach the total time, and then instead of stopping there it continued counting. So it almost works (though too slowly). I wonder it there's a way it could me made handle the larger file.

The following could be used as an input file for further testing. The <cr> are stripped but no <lf> is added. This is more or less equivalent to the posted input.txt (assuming the <cr> is not what's being searched for).

the first of several lines before the relevent section.
size=N/A time=00:03:49.12 bitrate=N/A speed= 458x size=N/A time=00:07:42.83 bitrate=N/A speed= 463x size=N/A time=00:11:34.91 bitrate=N/A speed= 463x size=N/A time=00:15:25.91 bitrate=N/A speed= 463x size=N/A time=00:19:17.53 bitrate=N/A speed= 463x size=N/A time=00:23:05.82 bitrate=N/A speed= 462x size=N/A time=00:26:57.58 bitrate=N/A speed= 462x size=N/A time=00:30:45.68 bitrate=N/A speed= 461x size=N/A time=00:34:32.26 bitrate=N/A speed= 460x size=N/A time=00:38:24.60 bitrate=N/A speed= 461x size=N/A time=00:42:15.26 bitrate=N/A speed= 461x size=N/A time=00:46:07.80 bitrate=N/A speed= 461x size=N/A time=00:49:59.72 bitrate=N/A speed= 461x size=N/A time=00:53:49.07 bitrate=N/A speed= 461x size=N/A time=00:57:35.87 bitrate=N/A speed= 461x size=N/A time=01:01:23.26 bitrate=N/A speed= 460x size=N/A time=01:05:09.72 bitrate=N/A speed= 460x size=N/A time=01:08:55.28 bitrate=N/A speed= 455x size=N/A time=01:12:43.57 bitrate=N/A speed= 455x size=N/A time=01:16:32.30 bitrate=N/A speed= 455x size=N/A time=01:20:20.95 bitrate=N/A speed= 455x size=N/A time=01:24:10.20 bitrate=N/A speed= 455x size=N/A time=01:27:56.10 bitrate=N/A speed= 455x size=N/A time=01:31:45.56 bitrate=N/A speed= 455x size=N/A time=01:35:37.43 bitrate=N/A speed= 456x size=N/A time=01:39:25.84 bitrate=N/A speed= 456x size=N/A time=01:43:15.64 bitrate=N/A speed= 456x size=N/A time=01:47:05.75 bitrate=N/A speed= 456x size=N/A time=01:50:56.02 bitrate=N/A speed= 456x size=N/A time=01:54:44.78 bitrate=N/A speed= 456x size=N/A time=01:58:35.83 bitrate=N/A speed= 456x size=N/A time=02:00:00.09 bitrate=N/A speed= 456x
the last line

Many thanks.

pieh-ejdsch
Posts: 240
Joined: 04 Mar 2014 11:14
Location: germany

Re: Find the last occurrence of a string in a file

#4 Post by pieh-ejdsch » 04 Dec 2016 13:30

If in your file no special characters exist - what is up to now the case - you can also use this Script.
It is a little more agile.

Code: Select all

setlocal
echo off
set "T=testfileA"
for /f "delims=" %%T in ('
 ^(for /f ^"delims^=^" %%i in ^(%T%^) do @for %%a in ^(%%i^) do @echo %%a^)^|findstr /r ^":[0-9][0-9]:^"
 ') do @set "lastTime=%%T"
set lastTime
pause


Phil

TTwrs1
Posts: 3
Joined: 03 Dec 2016 09:12

Re: Find the last occurrence of a string in a file

#5 Post by TTwrs1 » 04 Dec 2016 13:56

Phil, I was pulling my hair out for a week and couldn't get this working. Thanks SO much! Both versions you presented work, the second one much faster.

Could you perhaps give a brief explanation of how the second one works for our edification?

Many thanks again!. You saved my scalp... ;-)

Wayne

Post Reply