Arrays

From BR Wiki
Jump to navigation Jump to search

An array is a set of values that are grouped together, often logically related to each other.

An array allows you to refer to these related values by the array name and to use a number, called an index or subscript, to tell them apart. The individual values are called the elements of the array. They are contiguous from index 1 through the highest index value.

Example

The following example declares an array variable to hold the number of students in each grade in a grammar school.

Dim students(7)

The array students in the preceding example contains 7 elements. The indexes of the elements range from 1 through 7. Having this array is simpler than declaring 7 different variables.

The following illustration shows the array students. For each element of the array:

  • The index of the element represents the grade (index 1 represents kindergarten).
  • The value contained in the element represents the number of students in that grade.

00010 Dim students(7)
00020 let students(1)=25
00030 let students(2)=22
00040 let students(3)=29
00050 let students(4)=33
00060 let students(5)=24
00070 let students(6)=26
00080 let students(7)=27
00090 let MsgBox("Students in kindergarten = " & Str$(students(1)))
00100 let MsgBox("Students in first grade = " & Str$(students(2)))
00110 let MsgBox("Students in sixth grade = " & Str$(students(7)))

Dimensions

A dimension is a direction in which you can vary the specification of an array's elements. An array that holds the sales total for each day of the month has one dimension (the day of the month). An array that holds the sales total by department for each day of the month has two dimensions (the department number and the day of the month).

You specify an element of an array by supplying an index or subscript for each of its dimensions. The elements are contiguous along each dimension from index 1 through the highest index for that dimension.

The following illustrations show the conceptual structure of arrays with different dimensions. Each element in the illustrations shows the index values that access it. For example, you can access the first element of the second row of the two-dimensional array by specifying indexes (2, 1).

One-dimensional array

Two-dimensional array

Three-dimensional array

One Dimension

Many arrays have only one dimension, such as the number of people of each age. The only requirement to specify an element is the age for which that element holds the count. Therefore, such an array uses only one index. The following example declares a variable to hold a one-dimensional array of age counts for ages 0 through 120.

Dim ageCounts(120)

Two Dimensions

Some arrays have two dimensions, such as the number of offices on each floor of each building on a campus. The specification of an element requires both the building number and the floor, and each element holds the count for that combination of building and floor. Therefore, such an array uses two indexes. The following example declares a variable to hold a two-dimensional array of office counts, for buildings 1 through 40 and floors 1 through 5.

Dim officeCounts(40, 5)

A two-dimensional array is also called a rectangular array.

Three Dimensions

A few arrays have three dimensions, such as values in three-dimensional space. Such an array uses three indexes, which in this case represent the x, y, and z coordinates of physical space. The following example declares a variable to hold a three-dimensional array of air temperatures at various points in a three-dimensional volume.

Dim airTemperatures(99, 99, 24)

More than Three Dimensions

Although an array can have many dimensions, it is rare to have more than three.

Note that when you add dimensions to an array, the total storage needed by the array increases considerably, so use multidimensional arrays with care.

Working with Arrays

Programs often need to access every element of an array. Suppose you need to print the names and grades of all students in class, and that you have two arrays which contain the data you need - NAMES$ and GRADES. Below is one method you can use to achieve the result you wish:

00010 for studentNumber = 1 to udim(mat names$)
00020    print "Name  : "&NAMES$(studentNumber)
00030    print "Grade : "&str$(GRADES(studentNumber))
00040 next studentNumber

Here is the generic method of printing every element of array A$:

00010 for i=1 to udim(A$)
00020    print A$(i)
00030 next i

System Functions for working with Arrays

Srch

The Srch internal function searches an array and returns the row number matching the argument. If the argument is not found, then either 0 (BR 4.1 and below) or -1 (BR 4.2 and above). The argument must be the same data type (string or numeric) as the array. The optional "row" parameter defines the starting array element for the search.

SRCH(<array-name>,<argument>[,<row>])

OR

SRCH(<array-name$>,[^]<argument$>[,<row>])

Optional Case Insensitivity and Substring matching

If argument$ begins with the caret ^, then the ^ is stripped and the search for argument$ in array-name$ becomes case insensitive (as of 4.2). Also, when the caret ^ is specified, the search is performed for sub-strings instead of whole strings.

For example:

00010 let a$(1)='abc'
00020 let a$(2)='def'
00030 print srch(mat a$,'^B')

Output:

1

Given the (4.2+) SRCH use of the "^" character, to search for '^' with "let X=POS(string$,'^',5)" you will need to either turn the search character off with CONFIG SEARCH_CHAR OFF or replace the search character with something else as in CONFIG SEARCH_CHAR 7E (where 7E is the hexadecimal representation of an alternate search character).

Comments and Examples

As of 4.2, SRCH returns zero if it fails (instead of -1) unless OPTION BASE ZERO is in effect or OPTION 56 is in effect.

For versions 4.1 and earlier, when the search is unsuccessful, Srch returns -1. Using OPTION BASE 0 will also cause SRCH to return a zero.

In line 510 below, if STATES$ is a string array containing the 50 valid two-letter state abbreviations, then a data entry program could check whether the operator entered a correct abbreviation into the variable ST$ by the following:

500 LINPUT ST$
510 If Srch(Mat States$,ST$) = 0 then goto 500

The example below will find the selected item in a combo box

500 combo_choice$=srch(mat array-name$,"^^")

IMPORTANT

Earlier versions of BR return 0 when SRCH doesn't find the desired argument in the array. Later versions return -1 in the same situation. In order to make you programs produce the same results regardless of the BR version, use the following logic:

00010 if not SRCH(mat array$, string_to_find$) > 0 then
00020    ! add the code for when the result is NOT found
00030 else
00040    ! add the code for when the result IS found
00050 end if

Related Functions

Technical Considerations

  1. If a match was not found, Srch will return -1.


Mat

See Also: Mat for Beginners


The Mat (M) statement performs several array (or Matrix) operations. It can change the number of dimensions or elements, assign new values, and apply an expression to all elements. Each element is an individual variable.

MAT subarray operator

Arrays may now be subscripted with a starting and ending element number to process a portion of an array. This works much the same as Business Rules sub-string feature, except it works with elements instead of characters.

00100 MAT A(6:10)=B     ! copies B(1)..B(5) into A(6)..A(10);
00110 MAT B=A(6:10)     ! B dimensioned for 5 elements.
00120 MAT B(1:5)=A(6:10)  ! Copy part of 1 array to part of another
00130 READ MAT A(1:5)    ! only read elements 1-5
00140 PRINT FIELDS SF$:MAT A$(F:F+9) ! 10 elements starting at "F" are displayed

Multi-dimensional matrixes are not supported for sub-array processing.

Comments and Examples

Arrays and matrices are manipulated using the MAT statement. An array is a one-dimensional matrix. The MAT statement can be used to assign values to all elements of a matrix in a single statement. For example, MAT can be used to initialize all elements of an array to a constant as follows:

00100 MAT A = (0)
00200 MAT A$ = ("")

In the next example, values in one array are copied to another array:

00300 MAT A$ = B$
00400 MAT A = B

The MAT statement also handles mathematical operations on numeric arrays. Two arrays may be added or subtracted as follows:

00100 MAT A = B + C
00200 MAT A = B - C

Line 100 adds each element of matrix B to the corresponding element of matrix C and stores the result in the corresponding element of matrix A. The dimensions of A, B and C must be the same.

Another form of matrix arithmetic involves combining a matrix and a scalar. Business Rules adding, subtracting, multiplying, and dividing a number by all elements of a matrix. It is important to note that the scalar (X in the following examples) must be the left operand, and the matrix (B) must be the right operand. Due to these restrictions, subtraction and division must be accomplished in the manner illustrated in lines 500 and 600 below:

00300 MAT A=(X)+B
00400 MAT A=(X)*B
00500 MAT A=(-X)+B
00600 MAT A=(1/X)*B

In line 300, the numeric expression inside the parentheses is added to every element of matrix B; the result is stored in matrix A.

Array sorting is another feature of the MAT statement. Both string and numeric arrays can be sorted in ascending (AIDX) or descending (DIDX) order. The following is an example of using MAT AIDX to sort an array of names. The names are stored in array N$ and the number of names used is stored in L. See the AIDX function for another example.

00100 DIM A(100), N$(100)*30
00200 MAT N$(L)
00300 MAT A(L)=AIDX(N$)
00400 FOR I=1 TO L
00500  PRINT N$(A(I))
00600 NEXT I

Array A contains the indexed order of array N$, similar to the way an address-out sort file contains pointers to the original data. Lines 400 to 600 print the names in ascending order.

Lines 200 and 300 above illustrate another MAT function: redimensioning. The number of elements in an array or matrix can be increased or decreased. For example:

00100 DIM A(100), B(100)
00200 NA=200
00300 MAT A(NA)
00400 NB=50
00500 MAT B(NB)
00600 MAT A(NB)=B

Line 300 increases the number of elements of A to 200, and line 500 decreases the number of elements of B to 50. Line 600 illustrates copying array B into array A, while at the same time re-dimensioning A to have NB elements.

Re-dimensioning also allows you to change the number of dimensions. The following example changes matrix A from a 10 x 10 matrix to a one-dimensional array of 100 elements without changing the values of the elements of the matrix.

00100 DIM A(10,10)
00200 MAT A(100)=A

Syntax

MAT <array name> [(<dimension>[,...])] = {(<string expression>)|
    (<numeric expression>) <math operator> <numeric array> |
    <numeric array> +|- <numeric array> |
    <array name> |
    AIDX(<array name>)|
    DIDX(<array name>)}
    

Defaults

  1. No re-dimension.
  2. No assignment.
  3. Set the value of all elements to the expression.

Parameters

"Array-name" is a required parameter that represents a numeric or string array name. The optional "dimension" parameter is used to change the dimensions of the array mentioned in "array-name". Each dimension specification identifies the maximum size for that dimension. The dimension parameter is exactly the same as a combination of the "rows" and "columns" parameters described with the DIM statement, with the important distinction that any type of numeric expression may be used -not just integer constants.

"String-expr" can be used to set all the elements of an array to the same character string.

"Numeric-expr" represents expressions to be evaluated to a single value, which are used to make assignments to the matrix elements. It may be followed by one of four allowable "math operator" parameters: +, -, * or /. The math operator must then be followed by a "numeric array".

"Numeric array" is used in varieties of the MAT statement that perform arithmetic on arrays.

"AIDX" and "DIDX" are keywords used to invoke array functions for sorting an array in ascending (AIDX) or descending (DIDX) order. Both must be followed by an "array-name" within parentheses. Both create an index array, which is a numeric array containing numbers to be used as subscripts for accessing the original array in a sorted order. AIDX and DIDX can be used to sort either numeric or string arrays.

Technical Considerations

  1. Using re-dimensioning to decrease the number of elements saves memory and speeds up the AIDX and DIDX functions.
  2. When one matrix is assigned to another (via arithmetic or the AIDX/DIDX functions) the assigned-to matrix must be the same size as the assigned-from matrix. In the case of string matrices, the assigned-to matrix must have the same string length dimension as the assigned-from matrix; a SOFLOW condition will occur if the assigned-to string is too short.
  3. The expression to the right of the equal sign must be the same type (either numeric or string) as the array named on the left side.
  4. Re-dimensioning can increase or decrease the number of elements or the number of dimensions, but it cannot change the maximum lengths of string arrays.
  5. Use PRINT with the MAT keyword to print a matrix.
  6. Use READ with the MAT keyword to read data into an entire array.
  7. When matrixes are re-dimensioned, data is always preserved. When the size of a matrix is increased, the added elements are set to zero or null.
  8. Use CHAIN with the MAT keyword to chain an array assignment. (See the CHAIN statement for more information.)
  9. See the AIDX and DIDX Functions for more information.

Practical Uses

Mat can be used with read and data statements to put a lot of information into and easy to use array. For example, keeping forms together:

00100    data "8,2,c 6","8,9,c 30","8,39,c 1","8,40,c 30","9,2,c 9","9,12,c 30","9,43,c 6","9,50,c 15","9,65,c 7","9,73,c 2","10,2,c 9","10,12,c 7"
00110    read Mat Prinform$
...
00210    print fields Mat Prinform$: "Name: ",First$," ",Last$,"Address: ",Address$,"City: ",City$,"State: ",State$,"Zipcode: ",Zipcode$

Another common use is reading data from a file into arrays to print into a GRID:

00020     print Newpage
00030     dim Headings$(10), Widths(10), Forms$(10), Answers$(6)*30,Ordered(3), Head
00040     data "First Name","Last Name","Address","City","State","Zip Code","Shipping","Item 1","Item 2","Item 3"
00050     read Mat Headings$
00060     data 10,10,10,10,4,9,3,3,3,3
00070     read Mat Widths
00080     data "cc 30","cc 30","cc 30","cc 15","cc 2","cc 7","cc 1","n 1","n 1","n 1"
00090     read Mat Forms$
00100  !
00110     dim Firstname$(1)*30,Lastname$(1)*30,Address$(1)*30,City$(1)*15,State$(1)*2,Zipcodes$(1)*7,Shipmethod$(1)*1
00120  !
00130     open #1: "name=orders.INT,kfname=lastfirst.int,  recl=118,kps=31/1,kln=30/30,USE", internal, outin, keyed
00140  !
00150     mat Firstname$(0)
00160     mat Lastname$(0)
00170     mat Address$(0)
00180     mat City$(0)
00190     mat State$(0)
00200     mat Zipcodes$(0)
00210     mat Shipmethod$(0)
00270  !
00280  READTHENEXTONE: ! Ok
00290     read #1, using RECFORM: Mat Answers$,Shipping$,Mat Ordered eof DONEREADING
00300  RECFORM: form C 30,C 30,C 30,C 15,C 2,C 7,C 1,N 1,N 1,N 1
00310  !
00320     let Newsize=Udim(Firstname$)+1
00330  !
00340     mat Firstname$(Newsize)
00350     mat Lastname$(Newsize)
00360     mat Address$(Newsize)
00370     mat City$(Newsize)
00380     mat State$(Newsize)
00390     mat Zipcodes$(Newsize)
00400     mat Shipmethod$(Newsize)
00450  !
00460     let Firstname$(Newsize)=uprc$(Answers$(1))
00470     let Lastname$(Newsize)=Answers$(2)
00480     let Address$(Newsize)=Answers$(3)
00490     let City$(Newsize)=Answers$(4)
00500     let State$(Newsize)=Answers$(5)
00510     let Zipcodes$(Newsize)=Answers$(6)
00520     let Shipmethod$(Newsize)=Shipping$
00570  !
00580     goto READTHENEXTONE
00590  !
00600  DONEREADING: ! We're done reading, go to the nexst part, print them on  the list
00610  !
00620     print fields "2,2,grid 10/80,headers": (Mat Headings$,Mat Widths,Mat Forms$)
00630     print fields "2,2,grid 10/80,=r": (Mat Firstname$, Mat Lastname$,Mat Address$,Mat City$,Mat State$,Mat Zipcodes$,Mat Shipmethod$,Mat Item1,Mat Item2,Mat Item3)

Sorting Multidimensional Arrays

The following program illustrates using AIDX to sort both one dimensional arrays and two dimensional arrays. In the multi-dimensional example five rows of three strings are sorted by the first column of each row. The trick here is to select a key column and keep each row intact when transferring to another (sorted) array.

00010 ! Replace Aidx_Demo
00020 ! 
00030 ! Sample Code For Using Aidx
00040 ! 
00050 ! Last Revised 05/24/17
00060 ! 
00070    dim ONE_DIM1$(10)*100,TWO_DIM1$(5,3)*100,INDEX(1)
00080    dim ONE_DIM2$(10)*100,TWO_DIM2$(5,3)*100,WORK$(1)*100
00090 ! 
00100    execute "con console data_only"    !Keep console on during kstat
00110    let RND(555)                       !Same random numbers each run
00120 ! 
00130 ! ***** One Dimenional Sort
00140    for X = 1 to UDIM(ONE_DIM1$)
00150       let ONE_DIM1$(X) = STR$(RND)
00160    next X
00170    print MAT ONE_DIM1$
00180    print 
00190 ! 
00200    mat INDEX(UDIM(ONE_DIM1$)) = AIDX(ONE_DIM1$)
00210    for X = 1 to UDIM(ONE_DIM1$)
00220       let ONE_DIM2$(X) = ONE_DIM1$(INDEX(X))
00230    next X
00240    print MAT ONE_DIM2$
00250    print 
00260    print "Press Any Key..."
00270    let KSTAT$(1)
00280 ! 
00290 ! ***** Two Dimensional Sort
00300    for X = 1 to UDIM(TWO_DIM1$,1)
00310       for Y = 1 to UDIM(TWO_DIM1$,2)
00320          let TWO_DIM1$(X,Y) = STR$(RND) !Load random data
00330       next Y
00340    next X
00350    print MAT TWO_DIM1$                !Normal (original) form
00360 ! 
00370 ! Convert to one dimension for sorting
00380    let DIM1 = UDIM(TWO_DIM1$,1) !:
         let DIM2 = UDIM(TWO_DIM1$,2)
00390    mat TWO_DIM1$(DIM1 * DIM2)         !Restructure to 1 dimension
00400    print MAT TWO_DIM1$                !same data restructured
00410    print 
00420    print "Press Any Key..."
00430    let KSTAT$(1)
00440 ! 
00450    let KEY_COLUMN = 1
00460    mat WORK$(DIM1)                    !Space for row keys
00470    for X = 0 to DIM1-1
00480       let WORK$(X+1) = TWO_DIM1$(X*DIM2 +KEY_COLUMN)  !Get keys
00490    next X
00500    mat INDEX(DIM1) = AIDX(WORK$)      !Index rows
00510    mat TWO_DIM2$(DIM1 * DIM2)         !Restructure target array
00520 ! 
00530    for X = 0 to DIM1 -1               !For each 'to' row base 0
00540       let Y = INDEX(X+1) -1           !Get 'from' row base 0
00550       mat TWO_DIM2$(X*DIM2 +1:X*DIM2 +DIM2) = 
                TWO_DIM1$(Y*DIM2 +1:Y*DIM2 +DIM2)    !Copy sub array
00560    next X
00570    mat TWO_DIM1$(DIM1,DIM2)           !Restore source array
00580    mat TWO_DIM2$(DIM1,DIM2)           !Restructure target array
00590    print MAT TWO_DIM1$
00600    print 
00610    print MAT TWO_DIM2$

MAT Grouping

MAT grouping is now allowed in all full screen-processing statements. This feature allows you to indicate that input or output should alternate between all MAT variables that are specified within parentheses in the I/O list.

In the following code fragment, the A$ variable identifies the positions on the screen from which input values should be drawn. As usual, Business Rules will assign the first input value to the first element of B$. However, because the B$ and C matrices are specified within parentheses, it will then assign the second input value to the first element of C. The third value will go to B$, the fourth to C, and so on until both matrices are fully assigned. The last input value will go to X$.

00020 INPUT FIELDS A$: (MAT B$,MAT C),X$

Without MAT grouping, the above line must be coded as follows in order to achieve the same results (this example assumes that B$ and C have each been dimensioned for five elements):

 00020 INPUT FIELDS A$: B$(1),C(1),B$(2),C(2),B$(3),C(3),B$(4),C(4),B$(5),C(5),X$

MAT grouping is a lot easier to code, it executes faster, and most importantly it handles much larger arrays than are possible without using MAT grouping, as the resulting compiled line takes up less space in memory. The number of matrices that can be grouped together is 62, which in practical terms are no limit. All matrices in a group must have the same number of elements per matrix, or an error 0106 will result. Only MAT variables may be used in such groupings.

See error 0106 for additional information.




AIDX

AIDX (<array name>)

The AIDX internal function returns an array that is an ascending index obtained from sorting the array within parenthesis. The array to be sorted may be either string or numeric. The use of AIDX is permitted only in the MAT statement.

Note that you cannot use the Mat keyword in the array name parameter of this function.

Correct:

00010 MAT AscendingIndexArray(UDIM(ArrayToBeIndexed$))=AIDX(ArrayToBeIndexed$)

Incorrect:

00010 MAT AscendingIndexArray(UDIM(ArrayToBeIndexed$))=AIDX(MAT ArrayToBeIndexed$)

Comments and Examples

The program below will sort and print an array of names in alphabetical order:

00100 DIM A(100),N$(100)
00110 DATA "Tom", "Colleen", "Bill", "Christi"
00120 DATA "Tim", "Dave", "Sheila", "Jenni"
00130 DATA "Pam", "Laura", "Jean", "Michele"
00140 DATA "Gary", "Gordon", "Mallika"
00150 READ MAT N$ EOF 155
00155 MAT N$(CNT)
00160 MAT A(UDIM(N$))=AIDX(N$) ! 
00170 FOR I=1 TO 15
00180    PRINT N$(A(I))
00190 NEXT I

Related Functions

Other functions that operate on arrays are DIDX (array sort with descending index), SRCH, SUM and UDIM. See also MAT.

Technical Considerations

  1. The RD specification in BRConfig.sys can affect the AIDX function because it determines when two numeric values are considered equal.
  2. The COLLATE option in effect when the program was last saved or in the Option (statement) can alter the sort order from the AIDX function when sorting string values.
  3. To use AIDX, the arrays on both sides of the equal sign must have only one dimension and they must be the same number of elements.


DIDX

DIDX (<array name>)

The DIDX internal function returns an array that is a descending index obtained from sorting the array named. The array to be sorted may be either string or numeric. Only permitted in the MAT statement.

Note that you cannot use the Mat keyword in the array name parameter of this function.

Correct:

00010 MAT DescendingIndexArray(UDIM(ArrayToBeIndexed$))=AIDX(ArrayToBeIndexed$)

Incorrect:

00010 MAT DescendingIndexArray(UDIM(ArrayToBeIndexed$))=AIDX(MAT ArrayToBeIndexed$)

Comments and Examples

The program below will sort and print an array of names in reverse alphabetical order:

00100 DIM A(100),N$(100)
00110 DATA "Tom", "Colleen", "Bill", "Christi"
00120 DATA "Tim", "Dave", "Sheila", "Jenni"
00130 DATA "Pam", "Laura", "Jean", "Michele"
00140 DATA "Gary", "Gordon", "Mallika"
00150 READ MAT N$ EOF 155
00155 MAT N$(CNT)
00160 MAT A(UDIM(N$))=DIDX(N$) ! 
00170 FOR I=1 TO 15
00180    PRINT N$(A(I))
00190 NEXT I

Related Functions

Other functions that operate on arrays are

Technical Considerations

  1. DIdx will places equal array elements into ascending order by array index. In other words, for an array with three elements 10, 20 and 20, DIdx will return 2, 3, 1 (instead of 3, 2, 1).
  2. The RD specification in BRConfig.sys can affect the DIdx function because it determines when two numeric values are considered equal.
  3. The COLLATE option in effect when the program was last saved or in the OPTION statement can alter the sort order from the DIDX function when sorting string values.
  4. To use DIDX, the arrays on both sides of the equal sign must have the same dimensions.


SUM

SUM(<numeric array>)

The Sum internal function returns the sum of all the elements in the numeric array named.

SUM also works with multi-dimensional matrices.

Comments and Examples

00010 DIM X(8)
00020 DATA 2,5,3,4,6,3,4,5
00030 READ MAT X
00040 PRINT SUM(X)

Line 40 will print 32, which is the total of the elements of array X.

Related

See Also

Sort Control File Parameter SUM


UDIM

UDIM(<array name> [,<dimension>])


The UDim(A$,X) internal function returns the number of rows in the array if X=1. Returns the number of columns in the array if X=2. Returns the current size of dimensions 3, 4, 5, 6 or 7 when X is 3, 4, 5, 6 or 7. If the optional parameter X is omitted, UDIM returns the size of the first dimension.

Comments and Examples

00010 DIM A(15,20)
00020 PRINT UDIM(A), UDIM(A,1), UDIM(A,2)
00030 FOR I = 1 TO UDIM(A)
00040  FOR J = 1 TO UDIM(A,2)
00050   LET A(I,J) = I + J
00060  NEXT I
00070 NEXT J

The three numbers printed in line 20 will be 15, 15 and 20. Notice that by using UDIM in lines 30 and 40 this program can be changed to use a different sized two-dimensional array; the only programming change would be to change the dimensions in line 10 (or the array could be redimensioned using the MAT statement).

The following example increases the size of array arr$ by one element:

00010 mat arr$(udim(arr$)+1)

Related Functions

Other functions that operate on arrays are:

AIdx

DIdx

Srch

Sum



MAT2STR

Business Rules! 4.20 introduces the Mat2Str internal function which converts an array to a string

mat2str(MAT <Array Name>, <String Variable> [, [MAT] <Delimiter$>] [, "<Quote-Type>] [:] [<trim>]")

Parameters

"MAT Array Name" is the source array, from which you are building a string.

"String Variable" is the destination string that the function is creating.

"MAT Delimiter$" is a character that will be put after every entry from the array including the last entry. The delimiter can be "" which would simply concatenate the array. It is optional. As of 4.3 it can be an array.

"Quote Type" is optional, can be "Q", "QUOTES" , ' or " and is used to add quote processing to the string. This means that either a single or double quote will be placed around each of the source array's elements while creating the string. It's case insensitive.

If Q or QUOTES is specified then BR determines which quote type to apply like this: If the first element is contained in quotes, the quotes are stripped and any two consecutive quotes of the same kind become singles. Next the element is scanned left to right for either type of quote character (single or double). If a quote character is encountered the element is enclosed in the alternate quote type and embedded occurrences of that quote type are doubled. If no quote character is encountered then double quotes are applied.

"Trim" can be :LTRM , :TRIM or :RTRM and signifies the trim pre-processing of array elements. The colon is only used if preceded by a quote type.

Quote Processing Examples

Quote Type is Q or QUOTES

Array Element Part in the String Explanation
abcdef "abcdef" Normal processing of double quotes
abc'def "abc'def" A single quote embedded in an array element remains embedded in the string
abc"def 'abc"def' A double quote embedded in an array element remains embedded in the string
abc""def 'abc""def' Embedded quotes are left intact when quotes are not active
'abcdef "'abcdef" One single quote will be included in the string's double quotes.

Quote Type is ' (quote type single) When quote type is double, it mirrors quote type single.

Array Element Part of the String Explanation
abcdef 'abcdef' Normal processing of double quotes
'abcdef '''abcdef' A leading single quote is duplicated when embedded in single quotes
"abcdef '"abcdef' Leading double quote is included within the single quotes, like any other character

MAT2STR and STR2MAT trim outside of quotes but not inside of quotes.

MAT2STR always adds quotes when quotes are present in the data.

Defaults

1. The default Delimiter$ is CR on Linux or CRLF on Windows.

Other

1. Mat2Str performs the opposite action of Str2Mat.

2. Remember to dimension your resulting string.

3. When using MAT2STR on a 2 dimensional array, the first delimiter is used for individual elements and the second delimiter at the end of each row. This principle also applies to arrays containing three to seven dimensions. For example, given the following two dimensional array zzz$ containing the values:

   1            2
   3            4

The following statements-

00010 Sep$(1)=","
00020 Sep$(2)=hex$("0D0A") ! CRLF
00030 MAT2STR( MAT zzz$, str$, MAT Sep$ )
00040 PRINT str$

Will produce-

   1,2
   3,4

Examples

In the following code, we are making an array into a string separated by commas for printing.

! make the codes into one string for printing
let mat2str(Mat code$, MainString$, ",", "Q:trim")
print "The allowable codes include the following: "&mainstring$&"."

The output is as follows:

Without the "Q:trim", it would appear like this:

Example 2:

00010 dim resulting_String$*100, array$(3)
00020 let array$(1)="first"
00030 let array$(2)="second"
00040 let array$(3)="third"
00050 mat2str(mat array$,resulting_String$,"//")
00060 print resulting_String$

Output:

first//second//third


STR2MAT

The Str2Mat Internal Function will split a string variable based on a delimiter and place the resulting strings into an array which STR2MAT dynamically re-dimensions. The string to mat and mat to string functions have been extended to ease parsing of CSV and XML data (as of 4.3).

STR2MAT(<string variable>, MAT <array name>, [MAT] <delimiter$>, [<quote-type:trim>])

Parameters

"String Variable" is the variable that contains the data to be converted into an array.

"MAT array-name" is the name of the array into which the variable will be placed.

"Delimiter$" is a string containing the character in the string variable which will be used to separate it into items to be placed in the array. For example, a comma ",". In 4.3 Delimiter can be an array.

"Quotes:Trim" is an optional parameter which handles quotes within the string variable. Quotation marks can suppress the recognition of separators so that any delimiter (such as a comma) that occurs between the specified quotes will not split the data into separate array elements. Quote-type can be Q, QUOTES, ('), or ("), and is case insensitive. Q and QUOTES means that BR will recognize from the data which type of quotes (double or single) will be recognized by examining the first nonblank character. Q and QUOTES also means the enveloping quote characters will be stripped off of the data placed into the receiving array. The trim flags can be :LTRM , :TRIM or :RTRM , and denote post processing of extracted elements. In essence these indicate that leading and/or trailing blanks should be stripped from each resultant array element. The leading colon is only present when quote-type is specified (as of 4.3).

When examining str$ left to right, the first character (and the first character after each separator) is checked to see if is either (') or ("). If the first character is a quote, then it suppresses the recognition of separators until quotation processing is deactivated by another occurrence of the leading quote. The string is copied until it ends or until an odd number of successive occurrences of the governing quote type is encountered. During this processing, two adjacent occurrences of the governing quote character denote a single embedded occurrence of the quote character and is disregarded as a quote deactivator.

Defaults

Actually, the delimiter parameter is also optional in a sense. But practically speaking it is mandatory.

The default delimiter searches for the following combinations of line feed and carriage return characters:

This enables multiple CSV rows to be contained in a single string.

Further Explanation

1. When more than one occurrence of the same delimiters are used next to each other, BR honors all of them making an empty string element in the resulting array for all but the first occurrence of the delimiter. Consider the following example:

00010 let namelist$="Mary,John,,Salomi,Thomas,,,David,Sonia"
00020 str2mat(namelist$,mat customer$,",")
00030 print mat customer$

Output:

Mary
John

Salomi
Thomas


David
Sonia

Customer$(3), Customer$(6), and Customer$(7) would have a value of "".

2. If the delimiter is "", every character will be put in a separate element of the array.

3. Str2Mat performs the opposite action of Mat2Str

4. Str2Mat dynamically redimensions the array (mat customer$ in the above example) as needed to include all of the items from the source string variable. It returns the number in the final array.

5. When the delimiter is an array, both will signify the start of a new element in the final array. But when two consecutive delimiters are different, they will not create a blank element in the array. For example:

dim namelist$*256,customer$(7),delim$(2)
let namelist$="Mary,Jo.hn,,.Salomi.Thomas,,,David,,.Sonia"
let delim$(1)=","
let delim$(2)="."
str2mat(namelist$,mat customer$,Mat delim$)
print mat customer$

will return:

To restate this: when elements of a delimiter array occur adjacent to each other within the source string, they are grouped as one separator substring. When the same occur consecutively, it creates a null element in the final array output.

CSV Parsing Example (4.3)

The following code spinet demonstrates how to open a CSV/Tab File, read in the fields from the header, and then loop through the records.

01000    dim CSV_LINE$*999,CSV_FILE$*256, CSV_DELIM$*1,CSV_HEADER$*999,CSV_FIELDS$(1)*40,CSV_DATA$(1)*60
01020    form C," "
01040    let CSV_FILE$="Sample_File.tab" : let TAB$=CHR$(9)
01060    open #(CSV_HANDLE:=10): "name="&CSV_FILE$&",shr",display,input 
01080    linput #CSV_HANDLE: CSV_HEADER$
01100    let CSV_DELIM$=TAB$
01120    if POS(CSV_HEADER$,TAB$) <= 0 then 
01140       let CSV_DELIM$=","
01160    end if 
01180    let STR2MAT(CSV_HEADER$,MAT CSV_FIELDS$,CSV_DELIM$,"QUOTES:TRIM")
01200    print using 1020: MAT CSV_FIELDS$
01220    do 
01240       linput #CSV_HANDLE: CSV_LINE$ eof Exit_Csv
01260       let STR2MAT(CSV_LINE$,MAT CSV_DATA$,CSV_DELIM$,"Q:trim")
01280       print using 1020: MAT CSV_DATA$
01300    loop 
01320 Exit_Csv: !

You might wish to copy any CSV file to Sample_File.tab and run this program to view the content.

XML Parsing Enhancements

STR2MAT may also be used to Parse XML data.

This powerful tool is a bit more complex than parsing CSV files, but useful nonetheless.

The following example will parse XML$ into "MAT XML_LINE$"

 10 DIM XML$*999999,XML_LINE$(1)*32000
 20 XML$="<XML><NODE><ITEM>ITEM VALUE</ITEM></NODE></XML>"
 100 LET Str2mat(XML$,Mat XML_LINE$,">","TRIM")

This makes the parsing of XML a bit more convenient. The following XML sample shows how the function will parse the data

Data:

 <XML>
  <NODE>
    <ITEM>ITEM VALUE</ITEM>
  </NODE>
 </XML>

Results:

 <XML
 <NODE
 <ITEM
 ITEM VALUE</ITEM
 </NODE
 </XML

If the node names are known, a more complete and useful technique can be performed. You may use an array of Delimiter$ values to parse the data. Take the following example:

100    dim XML$*999999,XML_LINE$(1)*32000,DELIM$(4)*32
110    let XML$="<XML><NODE><ITEM>ITEM VALUE</ITEM><ITEM2>ITEM2 VALUE</ITEM2></NODE></XML>"
120    read MAT SEP$
130    data </XML>,</NODE>,</ITEM>,</ITEM2>
140    let STR2MAT(XML$,MAT XML_LINE$,MAT DELIM$,"TRIM")
150    print MAT XML_LINE$

This program would return the following results:

 <XML><NODE><ITEM>ITEM VALUE
 <ITEM2>ITEM2 VALUE

Notice that "Nested Nodes" are listed before the initial data, this may be used to identify the node.

Quote Processing Examples

The following chart demonstrates how data in the source string is handled if * and , are delimiters:

String Final Array Element Explanation
*"abc,def" abc,def the comma is not recognized as a separator and is part of the data since it is within quotes.
*abc"def abc"def embedded quotes may occur anywhere within a string after the first character
*"abc"def" abcdef" quotation processing is deactivated by the center quote mark
*"abcdef" abcdef normal data
*"abc'def" abc'def the single quote is treated like any other character while double quotes govern
*'abc"def' abc"def double quotes are treated like any other character while single quotes govern
*"abc""def" abc"def pairs of governing quotes denote a single embedded quote
*"abc"""def" abc"def" the third successive occurrence deactivates quote processing

Reading a CSV file

The following program takes this CSV file and uses STR2MAT to store the information in two separate arrays.

! This Sample Program Reads A Csv and puts it into two arrays, which could easily be written into a BR data file.
   dim Wholepiece$*10000, codelist$(1)*256, description$(1)*256, code$(1), nextline$*256

   open #1: "name=hcodeexport.csv, recl=500",display,input

   mat Code$(0)
   mat Description$(0)
   let delim$=","

   do while file(1)=0
      linput #1: nextline$ eof ignore
      if file(1)=0 then
         ! at this point we have 1 line of the CSV file in NextLine$
         let str2mat(nextline$,mat codelist$,delim$,"Q:trim")
 
         ! at this point we have mat CodeList$ sized 2 with each element in it
 
         ! lets do something useful, lets build them together into 2 arrays
         index=udim(mat code$) +1 ! find new position in the arrays
         mat Code$(index)         ! Make the arrays bigger
         mat Description$(index)
 
         ! Put the stuff we found into the new arrays
         let code$(index)=codelist$(1)
         let description$(index)=codelist$(2)
      end if
   loop
 
 ! print mat code$
 ! print mat description$
  for i=1 to 15
     print code$(i)&" "&description$(i)
  next i
   
  close #1:

Final Sample Program

The following program demonstrates quote processing and trimming, using both STR2MAT and MAT2STR:

00010 ! Rep Str2mat
00020    dim LINE$*400,DESC$(5)*30,SEP$(1)*20,QTYPE$(2)*20
00030 ! 
00040    print NEWPAGE
00050    let LINE$='"  TEST1",, " TEST,,3","TEST4" ,,"TE""S""T6 "'
00060    print LINE$;TAB(1);"no augmentation or quote recognition"
00070    print "note column 3 gets split up and quotes are data"
00080    let STR2MAT(LINE$,MAT DESC$,',')
00090    let MAT2STR(MAT DESC$,LINE$,',')
00100    for X = 1 to UDIM(DESC$) !:
            print DESC$(X), LEN(DESC$(X)) !:
         next X !:
         print LINE$
00110    linput Z$
00120 ! 
00130    print LINE$;TAB(1);"strip quotes and trim outside the quotes"
00140    print "convert commas to tildes"
00150    let STR2MAT(LINE$,MAT DESC$,',',"Q:TRIM")
00160    let MAT2STR(MAT DESC$,LINE$,'~')
00170    for X = 1 to UDIM(DESC$) !:
            print DESC$(X), LEN(DESC$(X)) !:
         next X !:
         print LINE$
00180    linput Z$
00190 ! 
00200    let LINE$='"  TEST1",, " TEST,,3","TEST4" ,,"TE""S""T6 "'
00210    print LINE$;TAB(1);"strip quotes and notrim"
00220    print "convert commas to tildes"
00230    print "column 3 is broken up because the leading quote is embedded without trim"
00240    let STR2MAT(LINE$,MAT DESC$,',',"Q")
00250    let MAT2STR(MAT DESC$,LINE$,'~')
00260    for X = 1 to UDIM(DESC$) !:
            print DESC$(X), LEN(DESC$(X)) !:
         next X !:
         print LINE$