home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / public_html / csv.save < prev    next >
Text File  |  2010-08-20  |  20KB  |  621 lines

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  2. <html lang="en">
  3. <head>
  4. <title>
  5. Kermit and Comma-Separated-Value Files
  6. </title>
  7. <META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  8. <META http-equiv="Content-Style-Type" content="text/css">
  9. <LINK REL=STYLESHEET TYPE="text/css" HREF="kermit.css">
  10. <LINK REL="shortcut icon" href="favicon.ico" >
  11. <style type="text/css">
  12.   ul li { padding-bottom:9;padding-right:64;line-height:12.5pt; }
  13.   h2, h3 { font-family: sans-serif }
  14.   h3 { border-top: 2px solid #999999 }
  15.   ul.contents li { line-height:10pt; font-family:sans-serif }
  16.   tt,pre { font-size:11pt }
  17.   dl.loose dd { padding:0 0 8 0 }
  18.   blockquote.example { margin-top:6; margin-bottom:8 }
  19.   body { color:black; background:white; margin:0; font-size:12pt">
  20.  
  21.  
  22. </style>
  23. </head>
  24.  
  25. <body>
  26.  
  27. <table cellpadding=0 cellspacing=0 width="100%"
  28.  style="border:1px solid darkmagenta; background-color:white;">
  29.  
  30. <tr style="background-image:url('lb3.jpg');">
  31. <td style="padding:8 8 8 8">
  32. <a style="text-decoration:none"
  33.  href="http://www.columbia.edu"><img
  34.  border=0
  35.  alt="The Columbia Crown"
  36.  title="The Columbia Crown (crown of King George II)"
  37.  height=105
  38.  src="crownico.gif"></a>
  39. <td align="left" style="padding-top:23">
  40. <tt style="font-size:24pt"><b>The Kermit Project</b></tt> |
  41. <span style="font-family:Ariel,times; font-size:18pt"><i>Columbia
  42.  University</i></span>
  43. <br><span style="font-family:Ariel,times; font-size:14pt">
  44. 612 West 115th Street, New York NY 10025 USA •
  45. <a href="mailto:kermit@columbia.edu">kermit@columbia.edu</a>
  46. </span>
  47. <table width="100%">
  48. <tr>
  49. <td style="font-size:12pt; font-style:italic">…since
  50.  <small>1981</small></div>
  51. </table>
  52.  
  53. <tr>
  54. <td colspan=2 style="padding:0">
  55. <table class=menu cellpadding=0 cellspacing=0
  56.  width="100%" style="border-top:1px solid darkmagenta">
  57. <tr>
  58. <td onClick="document.location.href='index.html';"
  59.  title="Kermit Project Home Page"
  60.  style="cursor:pointer"><a href="index.html">Home</a>
  61. <td onClick="document.location.href='k95.html';"
  62.  title="Kermit 95 for Windows"
  63.  style="cursor:pointer"><a href="k95.html">Kermit 95</a>
  64. <td class=this onClick="document.location.href='ckermit.html';"
  65.  title="C-Kermit for Unix and VMS"
  66.  style="cursor:pointer"><a href="ckermit.html">C-Kermit</a>
  67. <td onClick="document.location.href='ckscripts.html';"
  68.  title="Kermit Script Language and Tutorial"
  69.  style="cursor:pointer"><a href="ckscripts.html">Scripts</a>
  70. <td onClick="document.location.href='current.html';"
  71.  title="Current Versions of Kermit Software"
  72.  style="cursor:pointer"><a href="current.html">Current</a>
  73. <td onClick="document.location.href='new.html';"
  74.  title="What's New"
  75.  style="cursor:pointer"><a href="new.html">New</a>
  76. <td onClick="document.location.href='faq.html';"
  77.  title="Frequently Asked Questions"
  78.  style="cursor:pointer"><a href="faq.html">FAQ</a>
  79. <td onClick="document.location.href='support.html';"
  80.  style="border-right:0"
  81.  title="Kermit Software Support"
  82.  style="cursor:pointer"><a href="support.html">Support</a>
  83. </table>
  84. </table>
  85.  
  86. <div style="margin:8; font-family:calibri,sans-serif,times">
  87.  
  88. <div style="margin:8">
  89.  
  90. <div align="right" style="font-weight:bold; font-size:11pt">
  91. <span class=qq><a title="C-Kermit 9.0"
  92.  href="ck90.html">C-Kermit 9.0</a></span>
  93. </div>
  94.  
  95. <h2 style="margin-top:8">C-Kermit 9.0 and Comma-Separated-Value Files</h2>
  96.  
  97. <blockquote>
  98. Frank da Cruz<br>
  99. The Kermit Project<br>
  100. Columbia University<br>
  101. <i>Last update:</i>
  102. Fri Aug 20 14:02:34 2010
  103. </blockquote>
  104. <p>
  105.  
  106.  
  107. <div class=dm style="background:#eeeeee;border:1px solid plum; padding:0">
  108.  
  109. <ul style="font-size:14pt">
  110. <li><a href="#record"><b>Reading a CSV or TSV Record and Converting it
  111.  to an Array</b></a>
  112. <li><a href="#join"><b>Using \fjoin() to create a
  113.  Comma- or Tab-Separated Value List from an Array</b></a>
  114. <li><a href="#file"><b>Using CSV or TSV Files</b></a>
  115. </ul>
  116. </div>
  117. <p>
  118.  
  119. Comma-Separated Value (CSV) format is commonly output by spreadsheets and
  120. databases when exporting data into plain-text files for import into other
  121. applications.  It is important to understand the formal definition of a CSV
  122. file.
  123.  
  124. <ol>
  125.  
  126. <li>Each record is a series of fields.
  127.  
  128. <li>Records are in whatever format is used by the underlying file system
  129. for lines of text.
  130.  
  131. <li>Fields within records are separated by commas, with zero or more 
  132. whitespace characters (space or tab) before and/or after the comma.
  133.  
  134. <li>Fields with imbedded commas are enclosed in ASCII doublequote characters.
  135.  
  136. <li>Fields with leading or trailing spaces are enclosed in ASCII doublequotes.
  137.  
  138. <li>Fields with embedded doublequotes are enclosed in doublequotes and each
  139. interior doublequote is doubled.
  140.  
  141. </ol>
  142.  
  143. Here is an example:
  144.  
  145. <blockquote>
  146. <pre>
  147. aaa, bbb, has spaces,,"ddd,eee,fff", " has spaces ","Muhammad ""The Greatest"" Ali"
  148. </pre>
  149. </blockquote>
  150.  
  151. The first two are regular fields.  The second is a field that has an
  152. embedded space but in whichy any leading or trailing spaces are to be
  153. ignored.  The fourth is an empty field, but still a field.  The fifth is a
  154. field that contains embedded commas.  The sixth has leading and trailing
  155. spaces.  The last field has embedded quotation marks.
  156.  
  157. <p>
  158.  
  159. Prior to C-Kermit 9.0 Alpha.06, C-Kermit did not handle CSV files according
  160. to the specification above.  Most seriously, there was no provision for a
  161. separator to be surrounded by whitespace that was to be considered part of
  162. the separator.  Also there was no provision for quoting doublequotes inside
  163. of a quoted string.
  164.  
  165. <h3 id=record>Reading a CSV record</h3>
  166.  
  167. Now the <tt>\fsplit()</tt> function can handle any CSV-format string if you
  168. include the symbolic include set "CSV" as the 4th parameter.
  169. To illustrate, this program:
  170.  
  171. <blockquote>
  172. <pre>
  173. def xx {
  174.    echo [\fcontents(\%1)]
  175.    .\%9 := \fsplit(\fcontents(\%1), &a, \44, CSV)
  176.    for \%i 1 \%9 1 { echo "\flpad(\%i,3). [\&a[\%i]]" }
  177.    echo "-----------"
  178. }
  179. xx {a,b,c}
  180. xx { a , b , c }
  181. xx { aaa,,ccc," with spaces ",zzz }
  182. xx { "1","2","3","","5" }
  183. xx { this is a single field }
  184. xx { this is one field, " and this is another  " }
  185. xx { name,"Mohammad ""The Greatest"" Ali", age, 67 }
  186. exit
  187. </pre>
  188. </blockquote>
  189.  
  190. gives the following results:
  191.  
  192. <blockquote>
  193. <pre>
  194. [a,b,c]
  195.   1. [a]
  196.   2. [b]
  197.   3. [c]
  198. -----------
  199. [ a , b , c ]
  200.   1. [a]
  201.   2. [b]
  202.   3. [c]
  203. -----------
  204. [ aaa,,ccc," with spaces ",zzz ]
  205.   1. [aaa]
  206.   2. []
  207.   3. [ccc]
  208.   4. [ with spaces ]
  209.   5. [zzz]
  210. -----------
  211. [ "1","2","3","","5" ]
  212.   1. [1]
  213.   2. [2]
  214.   3. [3]
  215.   4. []
  216.   5. [5]
  217.   6. []   <span style="color:red">← Oops, this was fixed in Alpha.07</span>
  218. -----------
  219. [ this is a single field ]
  220.   1. [this is a single field]
  221. -----------
  222. [ this is one field, " and this is another  " ]
  223.   1. [this is one field]
  224.   2. [ and this is another  ]
  225.   3. []   <span style="color:red">← Ditto</span>
  226. -----------
  227. [ name,"Mohammad ""The Greatest"" Ali", age, 67 ]
  228.   1. [name]
  229.   2. [Mohammad "The Greatest" Ali]
  230.   3. [age]
  231.   4. [67]
  232. -----------
  233. </pre>
  234. </blockquote>
  235.  
  236. The separator <tt>\44</tt> (comma) must still be specified as the break set
  237. (3rd <tt>\fsplit()</tt> parameter).  When “CSV” is specified as
  238. the include set:
  239.  
  240. <ul>
  241. <li>The Grouping Mask is automatically set to 1 (which specifies that the
  242. ASCII doublequote character (<tt>"</tt>) is used for grouping;
  243. <li>The Separator Flag is automatically set to 1 so that adjacent field
  244. separators will not be collapsed;
  245. <li>All bytes (values 0 through 255) other than the break character are
  246. added to the include set;
  247. <li>Any leading whitespace is stripped from the first element unless it is
  248. enclosed in doublequotes;
  249. <li>Any trailing whitespace is trimmed from the end of the last element
  250. unless it is enclosed in doublequotes;
  251. <li>If the separator character has any spaces or tabs preceding it or
  252. following it, they are ignored and discarded;
  253. <li>The separator character is treated as an ordinary data character if
  254. it appears in a quoted field;
  255. <li>A sequence of two doublequote characters (<tt>""</tt>) within a quoted
  256. field is converted to a single doublequote.
  257. </ul>
  258.  
  259. There is also a new TSV symbolic include set, which is like CSV except
  260. without the quoting rules or the stripping of whitespace around the
  261. separator because, by definition, TSV fields do not contain tabs.
  262.  
  263. <p>
  264.  
  265. Of course you can specify any separator(s) you want with either the CSV,
  266. TSV, or ALL symbolic include sets.  For example, if you have a TSV file in
  267. which you want the spaces around each Tab to be discarded, you can use:
  268.  
  269. <blockquote>
  270. <pre>
  271. \fsplit(<i>variable</i>, &a, \9, CSV)
  272. </pre>
  273. </blockquote>
  274.  
  275. <tt>\9</tt> is Tab.
  276.  
  277. <p>
  278.  
  279. The new symbolic include sets can also be used with <tt>\fword()</tt>, which
  280. is just like <tt>\fsplit()</tt> except that it retrieves the
  281. <i>n</i><small>th</small> word from the argument string, rather than an
  282. array of all the words.  In C-Kermit you can get information about these or
  283. any other functions with the <small>HELP FUNCTION</small> command, e.g.:
  284.  
  285. <blockquote>
  286. <pre>
  287. C-Kermit> <u>help func word</u>
  288.  
  289. \fword(s1,n1,s2,s3,n2,n3) - Extract word from string.
  290.     s1 = source string
  291.     n1 = word number (1-based) counting from left; if negative, from right.
  292.     s2 = optional break set.
  293.     s3 = optional include set.
  294.     n2 = optional grouping mask.
  295.     n3 = optional separator flag:
  296.        0 = collapse adjacent separators
  297.        1 = don't collapse adjacent separators.
  298.  
  299.   Default break set is all characters except ASCII letters and digits.
  300.   ASCII (C0) control characters are treated as break characters by default.
  301.   Default include set is null.  Three special symbolic include sets are also
  302.   allowed: ALL (bytes not in the break set), CSV (special treatment
  303.   for Comma-Separated-Value records), and TSV (special treatment for Tab-
  304.   Separated-Value records).
  305.  
  306.   If grouping mask given and nonzero, words can be grouped by quotes or
  307.   brackets selected by the sum of the following:
  308.  
  309.      1 = doublequotes:    "a b c"
  310.      2 = braces:          {a b c}
  311.      4 = apostrophes:     'a b c'
  312.      8 = parentheses:     (a b c)
  313.     16 = square brackets: [a b c]
  314.     32 = angle brackets:  <a b c>
  315.  
  316.   Nesting is possible with {}()[]<> but not with quotes or apostrophes.
  317.  
  318. Returns string:
  319.   Word number n, if there is one, otherwise an empty string.
  320.  
  321. C-Kermit>
  322. </pre>
  323. </blockquote>
  324.  
  325. <h3 id=join>Using <tt>\fjoin()</tt> to create
  326.  Comma- or Tab-Separated Value Lists from Arrays</h3>
  327.  
  328. In Alpha.08 of C-Kermit 9.0, <tt>\fsplit()</tt>'s inverse function, <a
  329. href="ckermit80.html#fjoin"><tt>\fjoin()</tt></a> received the capability of
  330. converting an array into a comma-separated or a tab-separated value list.
  331. Thus, given a CSV, if you split it into an array with <tt>\fsplit()</tt> and
  332. then join the array with <tt>\fjoin()</tt>, giving each function the new CSV
  333. parameter in the appropriate argument position, the result will be will be
  334. equivalent to the original, according to the CSV definition.  It might not
  335. be identical, because if the result had extraneous spaces before or after
  336. the separating commas, these are discarded, but that does not affect the
  337. elements themselves.  The new syntax for <tt>\fjoin()</tt></a> is:
  338.  
  339. <p>
  340. <dl>
  341.  
  342. <dt><b><tt>\fjoin(&a,CSV)</tt></b>
  343. <dd>Given the array <tt>\&a[]</tt> or any other valid array designator,
  344. joins its elements into a comma-separated list according to the
  345. rules listed above.
  346.  
  347. <p>
  348.  
  349. <dt><b><tt>\fjoin(&a,TSV)</tt></b>
  350. <dd>Joins the elements of the given array into a tab-separated list, also
  351. described above.
  352. </dl>
  353. <p>
  354.  
  355. <a href="ckermit80.html#fjoin">Previous calling conventions for
  356. <tt>\fjoin()</tt></a> are undisturbed, including the ability to specify a
  357. portion of an array, rather than the whole array:
  358.  
  359. <p>
  360. <blockquote>
  361. <pre>
  362. declare \&a[] = 1 2 3 4 5 6 7 8 9
  363. echo \fjoin(&a[3:7],CSV)
  364. 3,4,5,6,7
  365. </pre>
  366. </blockquote>
  367. <p>
  368.  
  369. Using <tt>\fsplit()</tt> and <tt>\fjoin()</tt> is now possible to convert a
  370. comma-separated value list into a tab-separated value list, and vice versa
  371. (which is not a simple matter of changing commas to tabs or vice versa).
  372.  
  373.  
  374. <h3 id=join>Applications for CSV Files</h3>
  375.  
  376. Databases such as MS Access or MySQL can export tables or reports in CSV
  377. format, and then Kermit can read the resulting CSV file and do whatever you
  378. like with it; typically something that could not be done with the database
  379. query language itself (or that you didn't know how to do that way): create
  380. reports or datasets that based on complex criteria or procedures, edit or
  381. modify some fields, etc, and then use <tt>\fjoin()</tt> to put each record
  382. back in CSV form so it can be reimported into a spreadsheet or database.
  383.  
  384. <p>
  385.  
  386. Here is a simple example in which we purge all records of customers who have
  387. two or more unpaid bills.  The file is sorted in serial-number order.
  388.  
  389. <p>
  390. <blockquote>
  391. <pre>
  392. #!/usr/local/bin/kermit
  393. .filename = somefile.csv        # Input file in CSV format
  394. fopen /read \%c \m(filename)    # Open it
  395. if fail exit                    # Don't go on if open failed
  396. copy \m(filename) ./new         # Make a copy of the file
  397.  
  398. .oldserial = 00000000000        # Multiple records for each serial number
  399. .zeros = 0                      # Unpaid bill counter
  400.  
  401. while true {                    # Loop
  402.     fread /line \%c line        # Get a record
  403.     if fail exit                # End of file
  404.     .n := \fsplit(\m(line),&a,\44,CSV)    # Split the fields into an array
  405.     if not equ "\m(oldserial)" "\&a[6]" { # Have new serial number?   
  406.         # Remove all records for previous serial number
  407.         # if two or more bills were not paid...
  408.         if > \m(zeros) 1 {
  409.             grep /nomatch \m(oldserial) /output:./new2 ./new
  410.             rename ./new2 ./new
  411.         }
  412.         .oldserial := \&a[6]    # To detect next time serial number changes
  413.         .zeros = 0              # Reset unpaid bill counter
  414.     }
  415.     if equ "\&a[5]" "$0.00" {   # Element 5 is amount paid
  416.         increment zeros         # If it's zero, count it.
  417.     }
  418. }
  419. fclose \%c
  420. </pre>
  421. </blockquote>
  422. <p>
  423.  
  424. Rewriting the file multiple times is inelegant, but this is a quick and
  425. dirty use-once-and-discard script, so elegance doesn't count.
  426. The example is interesting in that it purges certain records based on
  427. the contents of other records.  Maybe there is a way to do this directly
  428. with SQL, but why use SQL when you can use Kermit?
  429.  
  430. <h3 id=file>Using CSV Files: Extending Kermit's Data Structures</h3>
  431.  
  432. Now that we can parse a CSV record, what would we do with a CSV <i>file</i>
  433. – that is, a sequence of records?  If we needed all the data available
  434. at once, we would want to load it into a matrix of (row,column) values.  But
  435. Kermit doesn't have matrices.  Or does it?
  436.  
  437. <p>
  438.  
  439. Kermit has several built-in data types, but you can invent your own data
  440. types as needed using Kermit's macro feature:
  441.  
  442. <blockquote>
  443. <pre>
  444. define <i>variablename value</i>
  445. </pre>
  446. </blockquote>
  447.  
  448. For example:
  449.  
  450. <blockquote>
  451. <pre>
  452. define alphabet abcdefghijklmnopqrstuvwxyz
  453. </pre>
  454. </blockquote>
  455.  
  456. This defines a macro named <i>alphabet</i> and gives it the value
  457. <i>abcdefghijklmnopqrstuvwxyz</i>.  A more convenient notation (added in
  458. C-Kermit 7.0) for this is:
  459.  
  460. <blockquote>
  461. <pre>
  462. .alphabet = abcdefghijklmnopqrstuvwxyz
  463. </pre>
  464. </blockquote>
  465.  
  466. The two are exactly equivalent: they make a literal copy the "right hand side"
  467. as the value of the macro.  Then you can refer to the macro anywhere in a
  468. Kermit command as "<tt>\m(</tt><i>macroname</i><tt>)</tt>":
  469.  
  470. <blockquote>
  471. <pre>
  472. echo "Alphabet = \m(alphabet)"
  473. </pre>
  474. </blockquote>
  475.  
  476. There is a second way to define a macro, which is like the first except that
  477. the right-hand side is <i>evaluated</i> first; that is, any variable
  478. references or function calls in the right-hand side are replaced by their
  479. values before the result is assigned to the macro.  The command for this is
  480. <small>ASSIGN</small> rather than <small>DEFINE</small>:
  481.  
  482. <blockquote>
  483. <pre>
  484. define alphabet abcdefghijklmnopqrstuvwxyz
  485. assign backwards \freverse(\m(alphabet))
  486. echo "Alphabet backwards = \m(backwards)"
  487. </pre>
  488. </blockquote>
  489.  
  490. which prints:
  491.  
  492. <blockquote>
  493. <pre>
  494. Alphabet backwards = zyxwvutsrqponmlkjihgfedcba
  495. </pre>
  496. </blockquote>
  497.  
  498. This kind of assignment can also be done like this: 
  499.  
  500. <blockquote>
  501. <pre>
  502. .alphabet = abcdefghijklmnopqrstuvwxyz
  503. .backwards := \freverse(\m(alphabet))
  504. </pre>
  505. </blockquote>
  506.  
  507. <a href="ckermit70.html#x7.9">Any command starting with a period is an
  508. assignment</a>, and the operator (<tt>=</tt> or <tt>:=</tt>) tells what to
  509. do with the right-hand side before making the assignment.
  510.  
  511. <p>
  512.  
  513. In both the <small>DEFINE</small> and <small>ASSIGN</small> commands, the
  514. variable name itself is taken literally.  It is also possible, however, to
  515. have Kermit <i>compute</i> the variable name.  This is done (as described
  516. in <a title="Using C-Kermit, 2nd Edition"
  517. href="http://www.amazon.com/gp/product/1555581641?ie=UTF8&tag=aleidmoreldom-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=1555581641"><i>Using
  518. C-Kermit</i></a>, 2nd Ed., p.457), using parallel
  519. commands that start with underscore: <small>_DEFINE</small> and
  520. <small>_ASSIGN</small> (alias <small>_ASG</small>).  These are just like
  521. <small>DEFINE</small> and <small>ASSIGN</small> except they evaluate the
  522. variable name before making the assigment.  For example:
  523.  
  524. <blockquote>
  525. <pre>
  526. define \%a one
  527. _define \%a\%a\%a 111
  528. </pre>
  529. </blockquote>
  530.  
  531. would create a macro named <small>ONEONEONE</small> with a value of 111, and:
  532.  
  533. <blockquote>
  534. <pre>
  535. define \%a one
  536. define number 111
  537. _assign \%a\%a\%a \m(number)
  538. </pre>
  539. </blockquote>
  540.  
  541. would create the same macro with the same value, but:
  542.  
  543. <blockquote>
  544. <pre>
  545. define \%a one
  546. define number 111
  547. _define \%a\%a\%a \m(number)
  548. </pre>
  549. </blockquote>
  550.  
  551. would give the macro a value of "<tt>\m(number)</tt>".
  552.  
  553. <p>
  554.  
  555. You can use the <small>_ASSIGN</small> command to create any kind of data
  556. structure you want; you can find some examples in the
  557. <a href="ckscripts.html#oops">Object-Oriented Programming</a> section of the
  558. <a href="ckscripts.html">Kermit Script Library</a>.  In the following
  559. program we use this capability to create a two-dimensional array, or matrix,
  560. to hold the all the elements of the CSV file, and then to display the matrix:
  561.  
  562. <blockquote>
  563. <pre>
  564. fopen /read \%c data.csv                # Open CSV file
  565. if fail exit 1
  566.  
  567. .\%r = 0                                # Row
  568. .\%m = 0                                # Maximum columns
  569. while true {
  570.     fread /line \%c line                # Read a record 
  571.     if fail break                       # End of file 
  572.     .\%n := \fsplit(\m(line),&a,\44,CSV) # Split record into items
  573.     incr \%r                            # Count this row
  574.     for \%i 1 \%n 1 {                   # Assign items to this row of matrix
  575.         _asg a[\%r][\%i] \&a[\%i]
  576.     }
  577.     if > \%i \%m { .\%m := \%i }        # Remember width of widest row
  578. }
  579. fclose \%c                              # Close CSV file 
  580. decrement \%m                           # (because of how FOR loop works) 
  581. echo MATRIX A ROWS: \%r COLUMNS: \%m    # Show the matrix
  582.  
  583. for \%i 1 \%r 1 {                       # Loop through rows
  584.     for \%j 1 \%m 1 {                   # Loop through columns of each row
  585.         xecho "\flpad(\m(a[\%i][\%j]),6)"
  586.     }
  587.     echo
  588. }
  589. exit 0
  590. </pre>
  591. </blockquote>
  592.  
  593. The matrix is called <tt>a</tt> and its elements are <tt>a[1][1]</tt>,
  594. <tt>a[1][2]</tt>, <tt>a[1][3]</tt>, ... <tt>a[2][1]</tt>, etc, and you can
  595. treat this data structure exactly like a two-dimensional array, in which you
  596. can refer to any element by its "X and Y coordinates".  For example, if the
  597. CSV file contained numeric data you could compute row and column sums using
  598. simple FOR loops and Kermit's built-in one-dimensional array data type:
  599.  
  600. <blockquote>
  601. <pre>
  602. declare \&r[\%r]                        # Make an array for the row sums
  603. declare \&c[\%m]                        # Make an array for the column sums
  604. for \%i 1 \%r 1 {                       # Loop through rows
  605.     for \%j 1 \%m 1 {                   # Loop through columns of each row
  606.         increment \&r[\%i] \m(a[\%i][\%j]) # Accumulate row sum
  607.         increment \&c[\%j] \m(a[\%i][\%j]) # Accumulate column sum
  608.     }
  609. }
  610. </pre>
  611. </blockquote>
  612.  
  613. Note that the sum arrays don't have to be initialized to zero because
  614. Kermit's <small>INCREMENT</small> command treats empty definitions as zero.
  615.  
  616. </div>
  617. <hr>
  618.  
  619. </body>
  620. </html>
  621.