HELP with "FOR LOOP" inside another

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
bodosko
Posts: 7
Joined: 17 Jun 2009 01:44

HELP with "FOR LOOP" inside another

#1 Post by bodosko » 22 Jun 2009 03:05

Hello,
I'm trying to do the following:

Code: Select all

for /F "tokens=1-2 delims=;" %%a in ('findstr /i "<Caption" "temp"') do (
   set /a counter+=1
   set /a N+=1
   for /F "tokens=1-2 delims=;" %%e in ('findstr /i "text;" "temp"') do (
      set /a counter2+=1
      if "!counter2!"=="!counter!" (
      echo %%b %%e %%f
      goto :eoloop
      )
   )
:eoloop
) >>"temp2"


The problem is that when the program leaves the second "for loop" it was supposed to continue on the first "for loop". But is leaves it too. I think it's because of the goto command.
But since I don't know too much about batch I need help on this.

Thanks

ghostmachine4
Posts: 319
Joined: 12 May 2006 01:13

#2 Post by ghostmachine4 » 22 Jun 2009 05:18

can you show your input file, your expected output?

bodosko
Posts: 7
Joined: 17 Jun 2009 01:44

#3 Post by bodosko » 22 Jun 2009 09:21

First, I just realize that since I have 2000 lines on my file, using loop inside another will take too much time to process. Is there any other way?

@ghostmachine4
Sure.
This is what I'm trying to do:

Transform this file format:

Code: Select all

time 00:00:00:00
text;blablabla
time 00:00:03:29
text;blablablablblablbalblalba
time 00:00:5:11
...


into this:

Code: Select all

00:00:00:00 --> 00:00:03:28
blablabla
00:00:03:29 --> 00:00:5:10
blablablablblablbalblalba
00:00:5:11 -> (NextTime -1ms)
and so on


Basically if I could put time1 (time2 - 1ms) and text on the same line, I could do the rest.

Thanks

avery_larry
Expert
Posts: 391
Joined: 19 Mar 2009 08:47
Location: Iowa

#4 Post by avery_larry » 22 Jun 2009 12:21

Code: Select all

@echo off
setlocal enabledelayedexpansion

for /f "tokens=1* delims=; " %%a in (tmp.txt) do (
   if %%a==time (
      for /f "tokens=1-4 delims=:" %%c in ("%%b") do (
         set ms=1%%f
         set ss=%%e
         set /a ms=ms%%100
         if !ms!==0 (
            set ms=99
            set ss=1!ss!
            rem Insert if !ss!=0 here and continue nested if's for coding nn:00:00:00 to nn-1:59:59:99
            set /a ss=ss%%100 - 1
            set ss=0!ss!
            set ss=!ss:~-2!
            ) else (
               set /a ms-=1
               set ms=0!ms!
               set ms=!ms:~-2!
         )
         set "time_range=!oldtime! --> %%c:%%d:!ss!:!ms!"
      )
      set oldtime=%%b
      if defined text (
         echo !time_range!>>tmp2.txt
         echo !text!>>tmp2.txt
      )
      ) else (
            set text=%%b
   )
)

ghostmachine4
Posts: 319
Joined: 12 May 2006 01:13

#5 Post by ghostmachine4 » 22 Jun 2009 18:42

if you have gawk for windows ,

Code: Select all

{o=$0}
NR==1{
   gsub(/:/,"",$2)
    last=$2
    s = o
    next
}
!/time/{lines[++d]=$0}
/time/ {   
   gsub(/:/,"",$2)      
   time = sprintf( "%08s",($2 - last) - 1)      
   print s "===> " format(time)
   for(i in lines) print lines[i]
   s=o   
   delete lines
   lasttime=s
   
}END{
   print lasttime
    for(i in lines) print lines[i]
}
function format(t, l){
   for(i=1;i<length(t);i+=2){
      l=l sprintf("%s%s:" , substr(t,i,1),substr(t,i+1,1))
   }
   sub(/:$/,"",l)
   return l
}


save the above as myscript.awk and on command line

Code: Select all

C:\test>more file.txt
time 00:00:00:00
text;blablabla
time 00:00:03:29
text;blablablablblablbalblalba
blahs.............
time 00:00:05:11
text 11111111111111111
text 222222222222222222
time 00:00:11:19
text 3333333333333333333333
time 00:00:23:00
text last line

C:\test>gawk -f test.awk file.txt
time 00:00:00:00===> 00:00:03:28
text;blablabla
time 00:00:03:29===> 00:00:05:10
text;blablablablblablbalblalba
blahs.............
time 00:00:05:11===> 00:00:11:18
text 11111111111111111
text 222222222222222222
time 00:00:11:19===> 00:00:22:99
text 3333333333333333333333
time 00:00:23:00
text last line


ghostmachine4
Posts: 319
Joined: 12 May 2006 01:13

#6 Post by ghostmachine4 » 22 Jun 2009 19:15

avery_larry wrote:

Code: Select all

@echo off
setlocal enabledelayedexpansion

for /f "tokens=1* delims=; " %%a in (tmp.txt) do (
   if %%a==time (
      for /f "tokens=1-4 delims=:" %%c in ("%%b") do (
         set ms=1%%f
         set ss=%%e
         set /a ms=ms%%100
         if !ms!==0 (
            set ms=99
            set ss=1!ss!
            rem Insert if !ss!=0 here and continue nested if's for coding nn:00:00:00 to nn-1:59:59:99
            set /a ss=ss%%100 - 1
            set ss=0!ss!
            set ss=!ss:~-2!
            ) else (
               set /a ms-=1
               set ms=0!ms!
               set ms=!ms:~-2!
         )
         set "time_range=!oldtime! --> %%c:%%d:!ss!:!ms!"
      )
      set oldtime=%%b
      if defined text (
         echo !time_range!>>tmp2.txt
         echo !text!>>tmp2.txt
      )
      ) else (
            set text=%%b
   )
)

does not meet the OP's requirement. what if there are multiple lines of text? what if you have to minus 1 from 00 milliseconds?

avery_larry
Expert
Posts: 391
Joined: 19 Mar 2009 08:47
Location: Iowa

#7 Post by avery_larry » 24 Jun 2009 09:13

what if there are multiple lines of text?


I guess you could imply that from this:

. . . and text on the same line


though by no means is that an explicit request of the OP.

what if you have to minus 1 from 00 milliseconds?


That's what this part of the code does:

Code: Select all

if !ms!==0 ( 
            set ms=99
            set ss=1!ss!
            rem Insert if !ss!=0 here and continue nested if's for coding nn:00:00:00 to nn-1:59:59:99
            set /a ss=ss%%100 - 1
            set ss=0!ss!
            set ss=!ss:~-2!
            ) else (
               set /a ms-=1
               set ms=0!ms!
               set ms=!ms:~-2!
         )

I just didn't take the time to finish the 2 or 3 additional nested if's required to complete it -- but it's all the exact same thing as already coded. Here's the extra 5 minutes of work for you:

Code: Select all

. . .
         set mm=%%d
         set hh=%%c
         set /a ms=ms%%100
         if !ms!==0 (
            set ms=99
            set ss=1!ss!
            set /a ss=ss%%100
            if !ss!==0 (
               set ss=59
               set mm=1!mm!
               set /a mm=mm%%100
               if !mm!==0 (
                  set mm=59
                  set hh=1!hh!
                  set /a hh=hh%%100 - 1
                  set hh=0!hh!
                  set hh=!hh:~-2!
                  ) else (
                     set /a mm-=1
                     set mm=0!mm!
                     set mm=!mm:~-2!
               )
               ) else (
                  set ss-=1
                  set ss=0!ss!
                  set ss=!ss:~-2!
            )
            ) else (
               set /a ms-=1
               set ms=0!ms!
               set ms=!ms:~-2!
         )
         set "time_range=!oldtime! --> !hh!:!mm!:!ss!:!ms!"
. . .


And for multiple lines of text:

Code: Select all

@echo off 
setlocal enabledelayedexpansion

for /f "tokens=1* delims=; " %%a in (tmp.txt) do (
   if %%a==time (
      for /f "tokens=1-4 delims=:" %%c in ("%%b") do (
         set ms=1%%f
         set ss=%%e
         set mm=%%d
         set hh=%%c
         set /a ms=ms%%100
         if !ms!==0 (
            set ms=99
            set ss=1!ss!
            set /a ss=ss%%100
            if !ss!==0 (
               set ss=59
               set mm=1!mm!
               set /a mm=mm%%100
               if !mm!==0 (
                  set mm=59
                  set hh=1!hh!
                  set /a hh=hh%%100 - 1
                  set hh=0!hh!
                  set hh=!hh:~-2!
                  ) else (
                     set /a mm-=1
                     set mm=0!mm!
                     set mm=!mm:~-2!
               )
               ) else (
                  set ss-=1
                  set ss=0!ss!
                  set ss=!ss:~-2!
            )
            ) else (
               set /a ms-=1
               set ms=0!ms!
               set ms=!ms:~-2!
         )
         set "time_range=!oldtime! --> !hh!:!mm!:!ss!:!ms!"
      )
      set oldtime=%%b
      if defined text (
         echo !time_range!>>tmp2.txt
         echo !text!>>tmp2.txt
         set text=
      )
      ) else (
            if not defined text (
               set text=%%b
               ) else (
                  set text=!text! %%b
            )
   )
)
if defined text (
   set "time_range=%oldtime% --> ??:??:??:??"
   echo !time_range!>>tmp2.txt
   echo !text!>>tmp2.txt
)
endlocal

bodosko
Posts: 7
Joined: 17 Jun 2009 01:44

#8 Post by bodosko » 24 Jun 2009 13:12

I'm having a problem...
Sometimes the file has just one line, but it's an extremely long line. (like 50000+ chars)
So with the FOR command the file doenst load, and doens't appear any warning error.

Why ?

jaffamuffin
Posts: 40
Joined: 25 Jan 2008 14:05

#9 Post by jaffamuffin » 24 Jun 2009 17:18

here's my attempt. Could be cleaned up a lot and I see someone has now posted a similar looking solution:

Code: Select all

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION
:fixtimes
SET currentline=0
for /F "tokens=1,2,3,4,5* delims=;: " %%A IN (in.txt) DO (
   IF "%%A"=="time" (
      
      SET hour=%%B
      SET mins=%%C
      SET secs=%%D
      SET msec=%%E
      SET prevtimevalue=!timevalue!
      SET timevalue=!hour!:!mins!:!secs!:!msec!
      rem echo !timevalue!
      
      SET previousline=!currentline!
      SET /A currentline=!currentline!+1
      rem echo !previousline!, !currentline!
      IF !previousline!==0 (
         REM START OF FILE DONT DO ANYTHING
         rem echo do ing nothing
      ) ELSE (
         REM NEED TO GET TIME - 1 ms
         call :gettimeless1ms newtime !hour! !mins! !secs! !msec!
         echo !prevtimevalue! --^> !newtime!
      )
   ) ELSE (
      IF !currentline! GTR 0 (
            IF "!textline!"=="" (
            
               IF "%%A"=="text" SET textline=%%A;%%B %%C %%D %%E %%F
            ) ELSE (
               echo !textline!
               IF "%%A"=="text" SET textline=%%A;%%B %%C %%D %%E %%F
            )
         )
      )
   )
      
   
   
)

GOTO :EOF
   
:gettimeless1ms
SET hourn=1%2
SET minsn=1%3
SET secsn=1%4
SET msecn=1%5




IF "!msecn!"=="100" (
   REM make 99 and sub 1 from secs
   SET msecn=199
            IF "!secsn!"=="100" (
               REM make 59 and sub 1 from mins
               SET secsn=159
                        IF "!minsn!"=="100" (
                           REM make 59 and sub 1 from hours
                           SET minsn=159
                                 IF "!hourn!"=="100" (
                                 REM ignore as no hours
                                 ) ELSE (
                                 SET /A hourn=hourn-1
                                 )
                        ) ELSE (
                           SET /A minsn=minsn-1
                        )
            ) ELSE (
               SET /A secsn=secsn-1
            )
) ELSE (
   SET /A msecn=msecn-1
)

REM echo !hourn!
REM echo !minsn!
REM echo !secsn!
REM echo !msecn!

SET hourn=!hourn:~1,2!
SET minsn=!minsn:~1,2!
SET secsn=!secsn:~1,2!
SET msecn=!msecn:~1,2!
REM echo !hour!:!mins!:!secs!:!msec!

   SET %1=!hourn!:!minsn!:!secsn!:!msecn!

GOTO :EOF
pause


in.txt:

Code: Select all

time 00:00:00:00 
text;blablabla
time 00:00:03:29
text;blablablablblablbalblalba
time 00:00:5:11
text;sadfsddsafasdf sd asdf msdf sdmf sdmf dsmf m
text;gfhffhdfghdf
time 00:00:7:00
text;s24234time 23:1:41:2 sdf sasf
time 03:00:00:00
text;s2dfasfasdf4234time 23:1:41:2 sdfsad dsaf sd df sdf sdf sdf sd d mmmmmmmmmmmmm


output

Code: Select all

W:\subs>W:\subs\subs2.bat
00:00:00:00 --> 00:00:03:28
text;blablabla
00:00:03:29 --> 00:00:5:10
text;blablablablblablbalblalba
text;sadfsddsafasdf sd asdf msdf sdmf sdmf dsmf m
00:00:5:11 --> 00:00:6:99
text;gfhffhdfghdf
00:00:7:00 --> 02:59:59:99
text;s24234time 23 1 41 2 sdf sasf


Seems to handle multiple text lines, handles single digits in the time code.
Probably needs adjusting to print the last line of text it dones't do that as there is no corresponding time for the 'next'


May miss out a semicolin on the text if it occurs within the fields 2-4 of the text. In that case you probalby want to use unix tools and regular expressions, or awk or something

avery_larry
Expert
Posts: 391
Joined: 19 Mar 2009 08:47
Location: Iowa

#10 Post by avery_larry » 25 Jun 2009 09:35

jaffamuffin -- I like the way you worked with the padded numbers -- just using 1XX (or 1X), do the math, and then strip the 1.

The way you have it, though, you'll have a problem with a single "0" (you mentioned it would work with single digit or padded numbers). I figured the input file was generated by some logging program and it would always have padded numbers (despite the example file having a single digit number).

The easy alternative, a bit of a hybrid between your approach and my approach -- is to add 100 instead of just prepending a "1":

Code: Select all

:gettimeless1ms 
SET /a hourn=100 + %2
SET /a minsn=100 + %3
SET /a secsn=100 + %4
SET /a msecn=100 + %5

and then the rest of the code works as you have it. (This approach will automatically pad any single digit numbers, not sure if that's good or bad.)

jaffamuffin
Posts: 40
Joined: 25 Jan 2008 14:05

#11 Post by jaffamuffin » 25 Jun 2009 11:47

Yes. I often do that, but if you perform a SET /A on a number that starts with 0 (zero) the interpreter interprets it an an Octal number, and could give 'weird' results, to saythe least :) My way means it doesn't matter but doing it by adding would mean the out put number would be padded, even if the input wasn't. Just depends exactly on the input file, and what the OP wants etc ... there's always more than one way to skin a cat.

Edit just looking at my output again, there's something funky happening with the multi line text. seems to split it over 2 times..... Probably just need to cache whether last thing read was a text or number or something.....

Also, it doesn't seem to have a problem with a single '0'. I did at one point have an issue, with the 5 becoming 15, but the string slicing removes the first character and keeps the next 2 (if there is only 1, it just takes the next 1)

jaffamuffin
Posts: 40
Joined: 25 Jan 2008 14:05

#12 Post by jaffamuffin » 25 Jun 2009 14:44

tried fixing my old code. Couldn't quite get the text associated with the correct timestamp so here's v2. This seems to work, except for the last line. ( which i can't seem to get)

Code: Select all

@echo off
SETLOCAL ENABLEDELAYEDEXPANSION



:fixtimes
IF EXIST tmp1.txt DEL tmp1.txt
SET currentsection=1
for /F "tokens=*" %%A IN (in.txt) DO (
   SET line=%%A
   SET linecheck=!line:~0,4!
   SET lineremainder=!line:~5!
   
   
   IF "!linecheck!"=="time" (
      IF "!lastlineinsectionwas!"=="text" SET /A currentsection=!currentsection!+1
      echo !currentsection!:time:!lineremainder!
      SET lastlineinsectionwas=time
   )
   IF "!linecheck!"=="text" (
      rem IF "!lastlineinsectionwas!"=="time" SET /A currentsection=!currentsection!+1
      echo !currentsection!:text:!lineremainder!
      SET lastlineinsectionwas=text
   )
)>>tmp1.txt

SET currentline=0
FOR /F "tokens=1,2,3,4,5,6,* delims=:" %%A IN (tmp1.txt) DO (
   IF "%%B"=="time" (
      SET section=%%A
      SET type=%%B
      SET hour=%%C
      SET mins=%%D
      SET secs=%%E
      SET msec=%%F
      SET prevtimevalue=!timevalue!
      SET timevalue=!hour!:!mins!:!secs!:!msec!
      rem echo !timevalue!
      
      SET previousline=!currentline!
      SET /A currentline=!currentline!+1
      rem echo !previousline!, !currentline!
      IF !previousline!==0 (
         REM START OF FILE DONT DO ANYTHING
         rem echo do ing nothing
      ) ELSE (
         REM NEED TO GET TIME - 1 ms
         call :gettimeless1ms newtime !hour! !mins! !secs! !msec!
                  SET timestamp=!prevtimevalue! --^> !newtime!
                  SET /A newsection=!section!-1
                  CALL :printtext !newsection! !timestamp!
                  REM echo !newsection!:!timestamp!
      )
   )
   
)
   
   goto:eof

:printtext
SET !newsection!=%1   
SET !timestamp!=%2
echo !timestamp!
FOR /F "tokens=1,2,* delims=:" %%A IN (tmp1.txt) DO (
   SET secti=%%A
   SET timeortext=%%B
   SET lineoftext=%%C
   REM echo !timeortext!
   REM echo !secti!
   REM echo !newsection!
   IF "!timeortext!"=="text" (
      IF "!secti!"=="!newsection!" (
         echo !lineoftext!
      )
   )
)

GOTO :EOF
   
:gettimeless1ms
SET hourn=1%2
SET minsn=1%3
SET secsn=1%4
SET msecn=1%5




IF "!msecn!"=="100" (
   REM make 99 and sub 1 from secs
   SET msecn=199
            IF "!secsn!"=="100" (
               REM make 59 and sub 1 from mins
               SET secsn=159
                        IF "!minsn!"=="100" (
                           REM make 59 and sub 1 from hours
                           SET minsn=159
                                 IF "!hourn!"=="100" (
                                 REM ignore as no hours
                                 ) ELSE (
                                 SET /A hourn=hourn-1
                                 )
                        ) ELSE (
                           SET /A minsn=minsn-1
                        )
            ) ELSE (
               SET /A secsn=secsn-1
            )
) ELSE (
   SET /A msecn=msecn-1
)

REM echo !hourn!
REM echo !minsn!
REM echo !secsn!
REM echo !msecn!

SET hourn=!hourn:~1,2!
SET minsn=!minsn:~1,2!
SET secsn=!secsn:~1,2!
SET msecn=!msecn:~1,2!
REM echo !hour!:!mins!:!secs!:!msec!

   SET %1=!hourn!:!minsn!:!secsn!:!msecn!

GOTO :EOF
pause


input

Code: Select all

time 00:00:00:00 
text;blablabla
time 00:00:03:29
text;blablablablblablbalblalba
time 00:0:5:11
text;sadfsddsafasdf sd asdf msdf sdmf sdmf dsmf m
text;gfhffhdfghdf
text;gfhf
time 00:00:7:00
text;s24234time 23:1:41:2 sdf sasf
time 03:00:00:00
text;s2dfasfasdf4234time 23:1:41:2 sdfsad dsaf sd df sdf sdf sdf sd d mmmmmmmmmmmmm


output

Code: Select all

W:\subs>subs3
00:00:00:00  --> 00:00:03:28
blablabla
00:00:03:29  --> 00:0:5:10
blablablablblablbalblalba
00:0:5:11 --> 00:00:6:99
sadfsddsafasdf sd asdf msdf sdmf sdmf dsmf m
gfhffhdfghdf
gfhf
00:00:7:00 --> 02:59:59:99
s24234time 23:1:41:2 sdf sasf

avery_larry
Expert
Posts: 391
Joined: 19 Mar 2009 08:47
Location: Iowa

#13 Post by avery_larry » 26 Jun 2009 09:09

jaffamuffin wrote:Yes. I often do that, but if you perform a SET /A on a number that starts with 0 (zero) the interpreter interprets it an an Octal number, and could give 'weird' results, to saythe least :)


Oh that's right -- it's why I do the % math--but I messed it up. I got the idea from this site, actually:

http://www.dostips.com/DtTipsDateTime.php

My code should have had:

set ms=100%%f
set /a ms=ms%%100
which will definitely strip any leading zeros (assuming that the unpadded number is always less than 100).

My way means it doesn't matter but doing it by adding would mean the out put number would be padded, even if the input wasn't.


Yes indeed. If you tweak your :gettimeless1ms routine then you'll get the complete solution (more on that below)
Just depends exactly on the input file, and what the OP wants etc ... there's always more than one way to skin a cat.

Edit just looking at my output again, there's something funky happening with the multi line text. seems to split it over 2 times..... Probably just need to cache whether last thing read was a text or number or something.....

Also, it doesn't seem to have a problem with a single '0'. I did at one point have an issue, with the 5 becoming 15, but the string slicing removes the first character and keeps the next 2 (if there is only 1, it just takes the next 1)
I meant that you would have trouble with a single 0 if you were subtracting -- since your if statement looks for "!msecn!"=="100", but with a single 0 it would be "10" instead of "100". Too bad there isn't an "OR" function in DOS.

Post Reply