is there a way to implement so called "record" and "field" data structure?

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
nnnmmm
Posts: 146
Joined: 26 Aug 2017 06:11

is there a way to implement so called "record" and "field" data structure?

#1 Post by nnnmmm » 30 Nov 2024 23:10

Code: Select all

@ECHO OFF
Setlocal EnableExtensions DisableDelayedExpansion
SetLocal EnableExtensions  EnableDelayedExpansion
SET CC=0
FOR %%V IN (
"AA 31"  D1
"BB 21"  "D2 2"
"CC 53"  D3
) DO (
   SET /A CC=!CC!+1
   ECHO !CC! "%%~V" 
)
REM PAUSE
:END
****************************************************************
the one above works but
is there a way to implement so called "record" and "field" data structure?
an idea is something like below but with a wrong batch grammar
@ECHO OFF
Setlocal EnableExtensions DisableDelayedExpansion
SetLocal EnableExtensions EnableDelayedExpansion
SET CC=0
FOR %%U %%V IN (
"AA 31" D1
"BB 21" "D2 2"
"CC 53" D3
) DO (
SET /A CC=!CC!+1
ECHO !CC! "%%U" "%%~V"
)
REM PAUSE
:END

miskox
Posts: 631
Joined: 28 Jun 2010 03:46

Re: is there a way to implement so called "record" and "field" data structure?

#2 Post by miskox » 01 Dec 2024 06:56

Why don't you make an example of what your output file should look like? We are all trying to guess.

I guess you are looking for a .txt file (you can call it a .csv file if you want):

Code: Select all

field1;field2;field3:field4;field5;
field1;field2;field3:field4;field5;
field1;field2;field3:field4;field5;
field1;field2;field3:field4;field5;
field1;field2;field3:field4;field5;
You can even have a 'key' in your file (I have lots of experience with indexed files (and COBOL) when I was still using OpenVMS):

Code: Select all

KKKKK;field1;field2;field3:field4;field5;
KKKKK;field1;field2;field3:field4;field5;
KKKKK;field1;field2;field3:field4;field5;
KKKKK;field1;field2;field3:field4;field5;
KKKKK;field1;field2;field3:field4;field5;
In the example above you can use FINDSTR /B /C:"KKKKK;---------YOUR KEY------------;" to find specific records. And when you get them you can process them with a FOR /F loop. (KKKKK can be avoided of course but you could add more info into a file with another special letters (LLLLL, MMMMM, NNNNN...) if 'key' values are the same. There are cases where I store my data in a .cmd itself (and I find this data with FINDSTR /B /C:"KKKKK..." - so I only have to copy one file instead of two (or more).

More info you provide better answers you will get (see viewtopic.php?f=3&t=11287 again).

Saso

T3RRY
Posts: 252
Joined: 06 May 2020 10:14

Re: is there a way to implement so called "record" and "field" data structure?

#3 Post by T3RRY » 01 Dec 2024 10:24

The below is my own implementation of this type of data structure, and includes a usage case example.

Edit: added some more remarks, modified delimiters / field seperators to cope with records containg field values that match fieldIDs within the record.

Code: Select all

@echo off & setlocal enableExtensions enableDelayedexpansion
CLS

(Set \n=^^^

%= do not modify this \n defintion =%)

===========================================================
rem macro usage:
:+ %@lookup% <recordVar> <returnVar> <fieldID> [fieldID]
rem  - returns the field value of the first matched
rem    fieldID in the record.
rem record data structure in format:
rem recordVar=;FieldID:fieldValue;FieldID:fieldValue;
rem  ; = fieldID initiator / field value terminator
rem  : = fieldID:fieldValue delimiter
rem if multiple field identidiers are matched, the return will be returned as a coma seperated list.
rem * NOTE * this macro definition is escaped for a enableDelayedExpansion environment.
Set @lookup=For %%. in (1 2)Do if %%.==2 (%\n%
  Set "#lookup=0"%\n%
  For /f "tokens=1,2,*" %%U in ("^!@.args^!")Do (%\n%
    Set "%%~V="%\n%
    For %%i in (%%W)Do (%\n%
      Set /a "#lookup+=1"%\n%
      If /i not "^!%%~U:;%%~i:=^!" == "^!%%~U^!" (%\n%
        Set "$lookup=^!%%U:*;%%~i:=^!"%\n%
        For /f "tokens=1 Delims=; EOL=" %%R in ("^!$lookup^!; ")Do (%\n%
          If not defined %%~V (%\n%
            Set "$lookup=%%R"%\n%
            Set "%%~V=%%R"%\n%
          ) else (%\n%
            If "^!%%~V^!"=="^!%%~V:%%R=^!" Set "%%~V=^!%%~V^!,%%R"%\n%
  ) ) ) ) )%\n%
)Else Set @.Args=

 Set "weekday.dat=;mon:Monday;tue:Tuesday;wed:Wednesday;thu:Thursday;fri:Friday;sat:Saturday;sun:Sunday;"
 Set "month.dat=;01:January;02:February;03:March;04:April;05:May;06:June;07:July;08:August;09:September;10:October;11:November;12:December;"
 Set "daynumber.dat=;01:1st;02:2nd;03:3rd;04:4th;05:5th;06:6th;07:7th;08:8th;09:9th;10:10th;11:11th;12:12th;13:13th;14:14th;15:15th;16:16th;17:17th;18:18th;19:19th;20:20th;21:21st;22:22nd;23:23rd;24:24th;25:25th;26:26th;27:27th;28:28th;29:29th;30:30th;31:31st;"

rem below usage examples assumes system language is english.
 for /f "usebackq delims=" %%G in (`PowerShell -Command "& {Get-Date -format 'dd/MM/yyyy'}"`) do set "$date=%%G"

 %@lookup% weekday.dat   $weekday   !date:~0,3!
 %@lookup% daynumber.dat $daynumber !$date:~0,2!
 %@lookup% month.dat     $month     !$date:~3,2!

 Echo !$weekday! the !$daynumber! of !$month! !$date:~-4!

Pause
Endlocal & goto:eof
Last edited by T3RRY on 02 Dec 2024 08:13, edited 2 times in total.

nnnmmm
Posts: 146
Joined: 26 Aug 2017 06:11

Re: is there a way to implement so called "record" and "field" data structure?

#4 Post by nnnmmm » 01 Dec 2024 18:26

>More info you provide better answers you will ..

this was what i did currently, i am using it but...
IF "%var1%"=="1" SET "D1=dostips" &SET "D2=%abc@zyx.com%" &SET D3=aaaa
IF "%var1%"=="2" SET "D1=ztree" &SET "D2=%zzz@poi.com%" &SET D3=cccc
IF "%var1%"=="3" SET "D1=youtube" &SET "D2=%txx@123.com%" &SET D3=vvvv

if i decided to alphabetically REORDER or INSERT new lines from above, it would be like below then i would have to change var1's number, and the display lines in ECHO command would also have to be changed
IF "%var1%"=="1" SET "D1=dostips" &SET "D2=%abc@zyx.com%" &SET D3=aaaa
IF "%var1%"=="4" SET "D1=linkbar" &SET "D2=%hhh@ggg.com%" &SET D3=kkkk
IF "%var1l%"=="3" SET "D1=youtube" &SET "D2=%txx@123.com%" &SET D3=vvvv
IF "%var1%"=="2" SET "D1=ztree" &SET "D2=%zzz@poi.com%" &SET D3=cccc

so i wanted to try a new data format that wouldnt need ordering and inserting and deleting as below
FOR %%V IN (
"AA 31" D1 11
"BB 21" "D2 2" 22
"CC 53" D3 33
) DO (

all i need is copy cut paste to REORDER, INSERT and etc
FOR %%V IN (
"BB 21" "D2 2" 22
"AA 31" D1 11
"zz" "D3 2" 44
"CC 53" D3 33

if i choose var1==2 as "record" number 2 then it brings out field21=%%U field22==%%V field23==%%W, was the idea i wanted to try
************************
FOR %%V IN ( .... ) DO ( output is everything one straight down
"AA 31"
D1
"BB 21"
"D2 2"

but if the idea FOR %%V %%U IN ( .... ) DO ( goes the way, the output will be
"AA 31" D1
"BB 21" "D2 2"
***********************************

for T3rry
it may take a while for me to try, my batch command and operator abilities are low
thanks for the time being

nnnmmm
Posts: 146
Joined: 26 Aug 2017 06:11

Re: is there a way to implement so called "record" and "field" data structure?

#5 Post by nnnmmm » 02 Dec 2024 07:36

>You can even have a 'key' in your file
not this way at the moment. keys automatically take whatever the order in which data are wrttien
example)
SetLocal EnableExtensions EnableDelayedExpansion
SET CC=0
FOR %%U IN (
A
E
D
B
) DO (
SET /A CC=!CC!+1
ECHO !CC! "%%~U"
)

!CC! number is the key, probably the simplest or the toughest if i have to deal with data strings with "!" in them
if %var%==27 echo get 27th !CC!'s %%U

and later....choice /C:1234567890abcdefghijklmnopqrstuvwxyz /N /M "Input:"
IF "%ErrorLevel%"=="33" echo get 33th !CC!'s %%U

if there is no easy way,
i will try to use // or ## as a divider to get this way
SET SS=%%U
SET S1=!SS:~3,10!
SET S2=!SS:~13,24!
SET S3=!SS:~30,44!


//"A 1" //"BB" //"2123"
//"AAAAA 1" //"BB BBBB" //"2123 DDDD"


********************
t3rry
i couldnt understand the code
sorry i couldnt put my data in the code you provided.

T3RRY
Posts: 252
Joined: 06 May 2020 10:14

Re: is there a way to implement so called "record" and "field" data structure?

#6 Post by T3RRY » 02 Dec 2024 09:17

For the sort of use cases you've exampled, the following example show how to use a string as the fieldID to extract the relevant field values. In light of the sort of examples you've included, I've incorporated my menu macro into the script to show a method of referencing the values using a related string

Code: Select all

@echo off & setlocal enableExtensions enableDelayedexpansion
CLS

(Set \n=^^^

%= do not modify this \n defintion =%)

===========================================================
rem macro usage:
:+ %@lookup% <recordVar> <returnVar> <fieldID> [fieldID]
rem  - returns the field value of the first matched
rem    fieldID in the record.
rem record data structure in format:
rem recordVar=;FieldID:fieldValue;FieldID:fieldValue;
rem  ; = fieldID initiator / field value terminator
rem  : = fieldID:fieldValue delimiter
rem if multiple field identidiers are matched, the return will be returned as a coma seperated list.
rem * NOTE * this macro definition is escaped for a enableDelayedExpansion environment.
Set @lookup=For %%. in (1 2)Do if %%.==2 (%\n%
  Set "#lookup=0"%\n%
  For /f "tokens=1,2,*" %%U in ("^!@.args^!")Do (%\n%
    Set "%%~V="%\n%
    For %%i in (%%W)Do (%\n%
      Set /a "#lookup+=1"%\n%
      If /i not "^!%%~U:;%%~i:=^!" == "^!%%~U^!" (%\n%
        Set "$lookup=^!%%U:*;%%~i:=^!"%\n%
        For /f "EOL= tokens=1 Delims=;" %%R in ("^!$lookup^!; ")Do (%\n%
          If not defined %%~V (%\n%
            Set "$lookup=%%R"%\n%
            Set "%%~V=%%R"%\n%
          ) else (%\n%
            If "^!%%~V^!"=="^!%%~V:%%R=^!" Set "%%~V=^!%%~V^!,%%R"%\n%
  ) ) ) ) )%\n%
)Else Set @.Args=

==================================================== REM = Menu macro Definition BEGIN
  REM Modular menu macro by T3RRY
  REM IMPORTANT - RESERVED VARIABLES: Menu* \n
  REM returns:
  REM Menu{String}
  REM Menu{Key}
  REM Menu{Number}

  REM Macro definition and expansion environment trickery pioneered by Jeb
  REM resources: 
  REM https://www.dostips.com/forum/viewtopic.php?t=9265#p60294
  REM https://www.dostips.com/forum/viewtopic.php?f=3&t=10983&sid=f6937e02068d93bc5a97ef63d4e5319e
  REM Macros with arguments learning resource:
  REM https://www.dostips.com/forum/viewtopic.php?f=3&t=1827

REM - use REM / remove REM on the below line to enable / disable menu dividing line
  REM Goto :NoDividingLine

  REM Enable DE environment to perform variable concatenation within a for loop
    Setlocal EnableDelayedExpansion

  REM Get console width for dividing line
    For /f "usebackq tokens=2* delims=: " %%W in (`mode con ^| %__APPDIR__%findstr.exe /LIC:"Columns"`) do Set /A "Console_Width=%%W"
    Set "Menu_Div=" & For /L %%i in (1 1 %Console_Width%)Do Set "Menu_Div=!Menu_Div!-"
    Endlocal & Set "Menu_Div=%Menu_Div%"

:NoDividingLine
  REM Menu internal variables
  REM keymap. translates literal keypress to the numeric position of the item in the menu list
    Set /a Menu@0=36,Menu@1=1,Menu@2=2,Menu@3=3,Menu@4=4,Menu@5=5,Menu@6=6,Menu@7=7,Menu@8=8,Menu@9=9,Menu@a=10,Menu@b=11,Menu@c=12,Menu@d=13,Menu@e=14,Menu@f=15,Menu@g=16,Menu@h=17,Menu@i=18,Menu@j=19,Menu@k=20,Menu@l=21,Menu@m=22,Menu@n=23,Menu@o=24,Menu@p=25,Menu@q=26,Menu@r=27,Menu@s=28,Menu@t=29,Menu@u=30,Menu@v=31,Menu@w=32,Menu@x=33,Menu@y=34,Menu@z=35
  REM Valid choice characters
    Set "Menu.Keys=123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0"

REM Menu macro Usage: %Menu% "quoted" "list of" "options"

%= Outer for loop allows environment independant definition =% For /f %%! in ("! ^! ^^^!") Do ^
%= IMPORTANT - No whitespace permitted here =%Set ^"Menu=For %%n in (1 2)Do if %%n==2 (%\n%
  If defined Menu{Args} (%\n%
    %= Switch control via !! Expansion outcome  =%  for /f "tokens=2" %%? in ("%%!%%! 1 0") do (%\n%
    %= Switch - Setlocal / NOP                  =%    If %%~? EQU 1 SetLocal EnableDelayedExpansion%\n%
    %= Output Dividing Line                     =%    If Defined Menu_Div Echo(%%!Menu_Div%%!%\n%
    %= Reset Menu.# index for Menu.Item[#]      =%    Set "Menu.#=0"%\n%
    %= Undefine choice command key list         =%    Set "Menu.Chars="%\n%
    %= For Each in list;                        =%    For %%G in (%%!Menu{Args}%%!)Do (%\n%
    %= For Menu.Item Index value                =%      For %%i in (%%!Menu.#%%!)Do If not %%i GTR 35 (%\n%
    %= Build the Choice key list                =%        Set "Menu.Chars=%%!Menu.Chars%%!%%!Menu.Keys:~%%i,1%%!"%\n%
    %= Define Menu.Item array                   =%        Set "Menu.Item[%%!Menu.Keys:~%%i,1%%!]=%%~G"%\n%
    %= Assign String for safe output            =%        Set "Menu.Output=%%~G"%\n%
    %= Display as [key] Option String           =%        Echo([%%!Menu.Keys:~%%i,1%%!] %%!Menu.Output%%!%\n%
    %= Increment Menu.# Index var               =%        Set /A "Menu.#+=1"%\n%
    %= Close Menu.# expansion loop              =%      )%\n%
    %= Close Menu{Args} String loop             =%    )%\n%
    %= Output Dividing Line                     =%    If Defined Menu_Div Echo(%%!Menu_Div%%!%\n%
    %= Select option by character index         =%    For /f "delims=" %%o in ('%__APPDIR__%Choice.exe /N /C:%%!Menu.Chars%%!')Do For /f "tokens=1,2 delims=;" %%V in ("%%!Menu.Item[%%o]%%!;%%!Menu@%%o%%!")Do (%\n%
    %= Switch - Endlocal / NOP ; returnVars     =%      ( If %%~? EQU 1 EndLocal ) ^& (%\n%
    %= exit [sub]script w/out modifying option  =%        If /I "%%V" == "Exit" Exit /B 2%\n%
    %= Assign 'Menu{String}' w/literal string   =%        Set "Menu{String}=%%V"%\n%
    %= Assign 'Menu{key}' with key pressed      =%        Set "Menu{Key}=%%o"%\n%
    %= Assign 'Menu{Number} with list position  =%        Set "Menu{Number}=%%~W"%\n%
    %= Reset Menu Argument variable             =%        Set "Menu{Args}="%\n%
    %= Close Menu macro processing loops        =%  )  )  )%\n%
  )%\n%
%= Capture Macro input - Options List       =%)Else Set Menu{Args}=^"
========================================== REM = Menu Macro Definition END

 Set @while=For %%z in (1 1 16)do if not defined $while
 Set "@while=Set $while=& !@while! !@while! !@while! !@while! "
 
 Set @getFieldIDs=For %%n in (1 2)do if %%n==2 (%\n%
   For /f "tokens=1,2" %%1 in ("^!@.args^!")Do (%\n%
     Set "%%2="%\n%
     Set "$record=^!%%1^!"%\n%
     if "^!%%1:~1^!" == ";" Set "$record=^!%%1:~1^!"%\n%
     if not "^!%%1:~-1^!" == ";" Set "$record=^!$record^!;"%\n%
     !@while! (%\n%
       If defined $record For /f "EOL=^| tokens=1,2 Delims=;:" %%i in ("^!$record^!") do (%\n%
         Set "%%2=^!%%2^! %%i"%\n%
         Set "$record=^!$record:*:=^!"%\n%
         Set "$record=^!$record:*;=^!"%\n%
       )Else Set "$while=stop"%\n%
     )%\n%
   )%\n%
 )Else Set @.args=

REM example usage:

 Set sites=;dostips:"D.2=abc^^^^^^^!@zyx.com" "D.3=aaaa";youtube:"D.2=txx@123.com" "D.3=vvvv";ztree:"D.2=zzz@poi.com" "D.3=cccc";Linkbar:"D.2=hhh@ggg.com" "D.3=kkkk"

 %@getFieldIDs% sites MenuList
 %menu% !MenuList!
 %@lookup% sites setup !Menu{String}!
 Set "D.1=!Menu{String}!"
 if defined setup For %%G in (!setup!)Do (
   Set "%%~G"
 )
 Set D.

Pause
Endlocal & goto:eof
Edit: I've amended the example to include a method of extracting all fieldIDs to generate menu options, to avoid having to
manually update such menus whenever you add a fieldID to the record.

Post Reply