Automic Workload Automation

Expand all | Collapse all

How to process an arbitrarily-sized list of items

  • 1.  How to process an arbitrarily-sized list of items

    Posted Nov 21, 2013 05:59 PM

    I would like to do something similar to the this for loop in bash:

     

    #!/bin/bash
    string_list="abc 123 xyz 789"
     for string in $string_list; do     echo $string done

    I tried to do it by creating create a string array and then acting on the elements of the array, but I ran into a problem: there seems to be no way to create a string array of arbitrary size — in other words, an array whose size is specified in a variable. The documentation suggests that it should work, but it does not.

    !  Split a comma-delimited string fill a new string array.
    :SET &LIST# = "abc,123,xyz,789"
    :SET &COUNT# = 4
    :DEFINE &COUNT#, unsigned
    :DEFINE &STRING_ARRAY#, string, &COUNT#
    :FILL &STRING_ARRAY#[] = STR_SPLIT("&LIST#", ",")
    :SET &INDEX# = 1
    :WHILE &INDEX# <= &COUNT#
    ! Do something, such as:
    :  SET &STRING# = &STRING_ARRAY#[&INDEX#]
    :  PRINT "String number &COUNT#: &STRING#"
    :ENDWHILE
    The Automation Engine demands that the Array size argument of the :DEFINE statement be an integer. If you try to put a variable in there, as above, it won’t even let you save the job. Obviously in this example, I could just use the number 4. However, I want to be able to handle a general case where the number of elements is not known ahead of time. Yes, know I could stick the items in a new temporary VARA and use PREP_PROCESS_VARA* to act on each item in the VARA — but creating an external object seems like overkill.

    I feel certain that this must be (or ought to be) a straightforward way to use UC4 scripting commands to go through an arbitrarily-sized list of items and act upon each the members. What’s the best way to do something like this?

    * Also, it would be nice if there were a PREP_PROCESS_ARRAY statement that would create a data sequence reference to an array, but this still depends on being able to create an arbitrarily-sized array in the first place.

    Thanks in advance.



  • 2.  How to process an arbitrarily-sized list of items

    Posted Nov 22, 2013 11:35 AM

     

     

     

     

    Here is some code that we developed a long time ago, Version 5.1 I think.  It is used quite extensively and perhaps would be applicable for your needs.

     

     

     

    ! COMMON_PARSE_DELIMITED_STRING Include
    !
    ! Parses a string variable.  Each piece, between the delimiter, is placed
    ! into the corresponding &piece_nn variable.  If there is no value between
    ! delimiters then the &piece_nn variable is set to a null value.
    !
    ! There are currently a maximum of 40 &piece_nn variables available. If
    ! more than 40 pieces are found in the &string_image then the variable
    ! &piece_max is set to "YES" for use by the caller.
    !
    ! Example of use:
    !
    ! : other code . . .
    ! :SET &string_image = '19051084,JOBP,SOME_JOB_PLAN_NAME,12,0-00-00 00:00:00,2008-01-28 10:36:23,00:00:00,60,FAULT_OTHER - Start impossible. Other error.,0,,,,,,,USER,,,,,,,,,,,,???'
    ! :SET &delim = ","  <===<< must set delimiter character <===<<
    ! :INC COMMON_PARSE_DELIMITED_STRING
    ! :PRINT "String length=&string_length, &pieces pieces found."
    ! :PRINT "&piece_01 &piece_02 &piece_03"
    ! : more code . . .
    !
    !
    :SET &piece_limit = 40
    :SET &piece_01 = ""
    :SET &piece_02 = ""
    :SET &piece_03 = ""
    :SET &piece_04 = ""
    :SET &piece_05 = ""
    :SET &piece_06 = ""
    :SET &piece_07 = ""
    :SET &piece_08 = ""
    :SET &piece_09 = ""
    :SET &piece_10 = ""
    :SET &piece_11 = ""
    :SET &piece_12 = ""
    :SET &piece_13 = ""
    :SET &piece_14 = ""
    :SET &piece_15 = ""
    :SET &piece_16 = ""
    :SET &piece_17 = ""
    :SET &piece_18 = ""
    :SET &piece_19 = ""
    :SET &piece_20 = ""
    :SET &piece_21 = ""
    :SET &piece_22 = ""
    :SET &piece_23 = ""
    :SET &piece_24 = ""
    :SET &piece_25 = ""
    :SET &piece_26 = ""
    :SET &piece_27 = ""
    :SET &piece_28 = ""
    :SET &piece_29 = ""
    :SET &piece_30 = ""
    :SET &piece_31 = ""
    :SET &piece_32 = ""
    :SET &piece_33 = ""
    :SET &piece_34 = ""
    :SET &piece_35 = ""
    :SET &piece_36 = ""
    :SET &piece_37 = ""
    :SET &piece_38 = ""
    :SET &piece_39 = ""
    :SET &piece_40 = ""
    !
    :SET &string_image = STR_CAT(&string_image,&delim)
    :SET &string_length = STR_LENGTH(&string_image)
    :SET &start = 1
    :SET &here = 1
    :SET &pieces = 0
    :SET &piece_max = "NO"
    !
    :WHILE &start LE &string_length
    : SET &found_delim = STR_FIND(&string_image,&delim,&start)
    : IF &found_delim GT 0
    !  Next delimiter found.
    :  SET &parse_length = SUB(&found_delim,&start)
    :  SET &string_piece = SUBSTR(&string_image,&start,&parse_length)
    :  IF STR_LENGTH(&string_piece) = 0
    :   SET &string_piece = ""
    :   ENDIF
    :  SET &pieces = ADD(&pieces,1)
    :  IF &pieces LE &piece_limit
    :   SET &parsed_piece = FORMAT(&pieces,"00")
    :   SET &parsed_piece = STR_CAT("piece_",&parsed_piece)
    :   SET_SCRIPT_VAR &parsed_piece = &string_piece
    :   SET &start = ADD(&start,&parse_length)
    :   SET &start = ADD(&start,1)
    :  ELSE
    :   SET &start = ADD(&string_length,1)
    !   More pieces exist than &pieces_nn variables, stop parsing.
    :   SET &piece_max = "YES"
    :   ENDIF
    : ELSE
    !  End of string reached, no delimiter found.
    :  SET &start = ADD(&start,1)
    :  IF &pieces = 0
    !   No delimiters found.
    :   SET &pieces = ADD(&pieces,1)
    :   SET &piece_01 = &string_image
    :   ENDIF
    :  ENDIF
    : ENDWHILE
    !
    :SET &pieces = FORMAT(&pieces)
    :SET &string_length = FORMAT(&string_length)
    ! End of Include


    Hope this helps.






  • 3.  How to process an arbitrarily-sized list of items

    Posted Nov 22, 2013 01:51 PM

    That’s quite helpful, and similar to what I ended up writing. It sure takes a lot of statements to do not very much.  :)  Thanks a bunch!



  • 4.  How to process an arbitrarily-sized list of items

    Posted Jan 02, 2014 11:08 AM

    Hallo, 

    I stumbled across this entry, because he was still taged as unanswered. Here is my version of the script by Mark:


    ! ************************************************************************************************
    ! Beschreibung: - Trennt eine Zeichenkette in Teilabschnitte und schreibt diese in Rückgabevariablen
    !               - Ermittelt die Anzahl der Teilabschnitte.
    !               - Ermittelt maximal 60 Teilabschnitte > &SPLIT_TEXTPART_1# bis &SPLIT_TEXTPART_60#
    !               - Das Trennzeichen (Delimiter) kann beliebig gewählt werden, darf aber nur 1 Zeichen lang sein.
    !               - Jedes Trennzeichen trennt 2 Teilabschnitte. D.h. ist am Ende der Zeichenkette ein Trennzeichen, wird
    !                 der leere Teil hinter dem Trennzeichen auch noch als Textabschnitt interpretiert und &SPLIT_TEXTPART_COUNT um 1 erhöht
    !                 "Hallo;Welt;" > &SPLIT_TEXTPART_COUNT# = 3, &SPLIT_TEXTPART_1# = "Hallo", &SPLIT_TEXTPART_2# = "Welt", &SPLIT_TEXTPART_3# bis &SPLIT_TEXTPART_60# = ""
    !                 "Hallo;Welt"  > &SPLIT_TEXTPART_COUNT# = 2, &SPLIT_TEXTPART_1# = "Hallo", &SPLIT_TEXTPART_2# = "Welt", &SPLIT_TEXTPART_3# bis &SPLIT_TEXTPART_60# = ""
    !
    ! !-----------------------------------------------------------------
    ! !Text in Teilabschnitte aufspalten
    ! !Übergabeparameter:
    ! :SET &SPLIT_TEXT# = "" .. Text
    ! :SET &SPLIT_DELIMITER# = "" .. Trennzeichen (darf max 1 Zeichen lang sein)
    ! :INC INCL.ALLG.SPLIT
    ! !Rückgabeparameter:
    ! :SET = &SPLIT_TEXTPART_COUNT# .. Anzahl der Textabschnitte im übergebenen String
    ! :SET = &SPLIT_TEXTPART_1# .. Erster Textabschnitt
    ! :SET = &SPLIT_TEXTPART_2# .. Zweiter Textabschnitt
    ! !...
    ! :SET = &SPLIT_TEXTPART_60# .. Maximal können 60 Textabschnitte ermittelt werden
    ! !-----------------------------------------------------------------
    !
    ! Datum      Autor    Beschreibung
    ! -----------------------------------------
    ! 19.03.12   SGU      Erstellung
    ! ***********************************************************************************************************
    !
    :SET &SPLIT_TEXTPART_COUNT# = 0
    :SET &DELIMITER_POS# = 0
    :SET &ACT_POS# = 0
    !
    :SET &SPLIT_TEXTPART_1# = ""
    :SET &SPLIT_TEXTPART_2# = ""
    :SET &SPLIT_TEXTPART_3# = ""
    :SET &SPLIT_TEXTPART_4# = ""
    :SET &SPLIT_TEXTPART_5# = ""
    :SET &SPLIT_TEXTPART_6# = ""
    :SET &SPLIT_TEXTPART_7# = ""
    :SET &SPLIT_TEXTPART_8# = ""
    :SET &SPLIT_TEXTPART_9# = ""
    :SET &SPLIT_TEXTPART_10# = ""
    :SET &SPLIT_TEXTPART_11# = ""
    :SET &SPLIT_TEXTPART_12# = ""
    :SET &SPLIT_TEXTPART_13# = ""
    :SET &SPLIT_TEXTPART_14# = ""
    :SET &SPLIT_TEXTPART_15# = ""
    :SET &SPLIT_TEXTPART_16# = ""
    :SET &SPLIT_TEXTPART_17# = ""
    :SET &SPLIT_TEXTPART_18# = ""
    :SET &SPLIT_TEXTPART_19# = ""
    :SET &SPLIT_TEXTPART_20# = ""
    :SET &SPLIT_TEXTPART_21# = ""
    :SET &SPLIT_TEXTPART_22# = ""
    :SET &SPLIT_TEXTPART_23# = ""
    :SET &SPLIT_TEXTPART_24# = ""
    :SET &SPLIT_TEXTPART_25# = ""
    :SET &SPLIT_TEXTPART_26# = ""
    :SET &SPLIT_TEXTPART_27# = ""
    :SET &SPLIT_TEXTPART_28# = ""
    :SET &SPLIT_TEXTPART_29# = ""
    :SET &SPLIT_TEXTPART_30# = ""
    :SET &SPLIT_TEXTPART_31# = ""
    :SET &SPLIT_TEXTPART_32# = ""
    :SET &SPLIT_TEXTPART_33# = ""
    :SET &SPLIT_TEXTPART_34# = ""
    :SET &SPLIT_TEXTPART_35# = ""
    :SET &SPLIT_TEXTPART_36# = ""
    :SET &SPLIT_TEXTPART_37# = ""
    :SET &SPLIT_TEXTPART_38# = ""
    :SET &SPLIT_TEXTPART_39# = ""
    :SET &SPLIT_TEXTPART_40# = ""
    :SET &SPLIT_TEXTPART_41# = ""
    :SET &SPLIT_TEXTPART_42# = ""
    :SET &SPLIT_TEXTPART_43# = ""
    :SET &SPLIT_TEXTPART_44# = ""
    :SET &SPLIT_TEXTPART_45# = ""
    :SET &SPLIT_TEXTPART_46# = ""
    :SET &SPLIT_TEXTPART_47# = ""
    :SET &SPLIT_TEXTPART_48# = ""
    :SET &SPLIT_TEXTPART_49# = ""
    :SET &SPLIT_TEXTPART_50# = ""
    :SET &SPLIT_TEXTPART_51# = ""
    :SET &SPLIT_TEXTPART_52# = ""
    :SET &SPLIT_TEXTPART_53# = ""
    :SET &SPLIT_TEXTPART_54# = ""
    :SET &SPLIT_TEXTPART_55# = ""
    :SET &SPLIT_TEXTPART_56# = ""
    :SET &SPLIT_TEXTPART_57# = ""
    :SET &SPLIT_TEXTPART_58# = ""
    :SET &SPLIT_TEXTPART_59# = ""
    :SET &SPLIT_TEXTPART_60# = ""
    !
    :SET &SPLIT_TEXT# = "&SPLIT_TEXT#&SPLIT_DELIMITER#"
    :SET &STRING_LEN# = STR_LNG(&SPLIT_TEXT#)
    !
    :WHILE &DELIMITER_POS# < &STRING_LEN#
    :  SET &ACT_POS# = add(&DELIMITER_POS#, 1)
    :  SET &SPLIT_TEXTPART_COUNT# = add(&SPLIT_TEXTPART_COUNT#, 1)
    :  SET &SPLIT_TEXTPART_COUNT# = format(&SPLIT_TEXTPART_COUNT#)
    :  SET &DELIMITER_POS# = str_find(&SPLIT_TEXT#, &SPLIT_DELIMITER#, &ACT_POS#)
    :  SET &VALUE_LEN# = sub(&DELIMITER_POS#, &ACT_POS#)
    :  SET &VALUE# = STR_CUT(&SPLIT_TEXT#, &ACT_POS#, &VALUE_LEN#)
    !
    :  SET_SCRIPT_VAR "SPLIT_TEXTPART_&SPLIT_TEXTPART_COUNT#" = &VALUE#
    !
    :ENDWHILE




  • 5.  How to process an arbitrarily-sized list of items

    Posted Jan 08, 2014 11:19 AM

    Both of the above answers are capable of processing lists ofup to nitems, where n is a limited integer (40 in the first answer, and 60 in the most recent one). I really appreciate the replies, but I was really hoping that there were a general solution.




  • 6.  How to process an arbitrarily-sized list of items
    Best Answer

    Posted Jan 09, 2014 06:39 AM
    There really isn't a completely generic solution as you have pointed out the :DEFINE statement when creating an array requires an integer (not an integer variable) to define the size of the array.

    I tend to use an arbitrary large number to define the array and then process the array in a :WHILE loop with the constraint that the item at the current index <> ""

    :DEFINE &MYARRAY#, string, 1000
    :SET &INDEX# = 1

    ! Populate the array ...

    :WHILE &MYARRAY#[&INDEX#] <> ""
    ! do something
    :  SET &INDEX# = &INDEX# + 1
    :ENDWHILE

    Another alternative is to add the elements you would put in the array into a static VARA and use PREP_PROCESS_VARA().

    The only way I know of to get a dynamically sized array is via the :FILL command.



  • 7.  How to process an arbitrarily-sized list of items

    Posted Jan 09, 2014 11:46 AM
    There really isn't a completely generic solution as you have pointed out the :DEFINE statement when creating an array requires an integer (not an integer variable) to define the size of the array.

    I tend to use an arbitrary large number to define the array and then process the array in a :WHILE loop with the constraint that the item at the current index <> ""

    :DEFINE &MYARRAY#, string, 1000
    :SET &INDEX# = 1

    ! Populate the array ...

    :WHILE &MYARRAY#[&INDEX#] <> ""
    ! do something
    :  SET &INDEX# = &INDEX# + 1
    :ENDWHILE

    Another alternative is to add the elements you would put in the array into a static VARA and use PREP_PROCESS_VARA().

    The only way I know of to get a dynamically sized array is via the :FILL command.

    I think the :WHILE approach is a pretty good one. This approach requires the declaration of just one variable, albeit an array with a large size.

    The :FILL command is great; it would be even more useful if there were a corresponding PREP_PROCESS_ARRAY() command.

    I think there ought to be an STR_COUNT() command too, that returns the number of instances of a substring within a string.

    Thanks for the reply!



  • 8.  How to process an arbitrarily-sized list of items

    Posted Jul 02, 2015 03:53 PM
    I don't see a solution here that takes advantage of data sequences, so I'll add one. I'm using the prefix I_PAR_ to create a namespace for the include. This should work for leading, trailing, and multi-character delimiters. In the end, you have a data sequence containing the tokens that you can process in a loop.

    :set &I_PAR_line# = ",file1,,file2,file3,"
    :set &I_PAR_delimiter# = ","
    :print &I_PAR_line#
    !
    !-------------------------------------
    !
    !  Extract the tokens
    !
    :set &I_PAR_count# = "0"
    :set &I_PAR_delimiterLength# = str_length(&I_PAR_delimiter#)
    :set &I_PAR_delimiterLenPlusOne# = &I_PAR_delimiterLength# + 1
    :set &I_PAR_TOKEN_LIST# = create_process(NEW)
    :while str_length(&I_PAR_line#)> 0
    :  set &I_PAR_index# = str_find(&I_PAR_line#, &I_PAR_delimiter#)
    !
    !  Line starts with delimiter
    :  if &I_PAR_index# = 1
    :    if str_length(&I_PAR_line#) >= &I_PAR_delimiterLenPlusOne#
    :      set &I_PAR_line# = str_cut(&I_PAR_line#, &I_PAR_delimiterLenPlusOne#)
    :    else
    :      set &I_PAR_line# = ""
    :    endif
    :  else
    !
    !  Line starts with token
    !
    !    Get current token
    :    if &I_PAR_index# <> 0
    :      set &I_PAR_tokenLength# = &I_PAR_index# - 1
    :      set &I_PAR_token# = str_cut(&I_PAR_line#, 1, &I_PAR_tokenLength#)
    :      set &I_PAR_line# = str_cut(&I_PAR_line#, &I_PAR_index#)
    :    else
    !      Last token
    :      set &I_PAR_token# = str_cut(&I_PAR_line#, 1)
    :      set &I_PAR_line# = ""
    :    endif
    :    set &ret# = put_process_line(&I_PAR_TOKEN_LIST#, &I_PAR_token#)
    :  endif
    :endwhile
    !
    !----------------------------------------
    !
    !  Process list of tokens
    !
    :print ""
    :process &I_PAR_TOKEN_LIST#
    :  set &token# = get_process_line(&I_PAR_TOKEN_LIST#)
    :  print &token#
    :endprocess
    :close_process &I_PAR_TOKEN_LIST#


  • 9.  How to process an arbitrarily-sized list of items

    Posted Jul 06, 2015 03:22 AM
    I suppose one could just perform actions on the data inside the while loop; however, putting the data into a data sequence does allow greater flexibility. Thanks for the answer, MikeBurnham603785.


  • 10.  How to process an arbitrarily-sized list of items

    Posted Jul 07, 2015 05:12 PM
    I was thinking of the code inside of the hyphen lines as something you'd break out to an include for reuse, otherwise yeah no reason to loop through twice.