unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* simple first emacs script
@ 2010-12-15 12:55 Tom
  2010-12-15 14:51 ` Pascal J. Bourguignon
  0 siblings, 1 reply; 7+ messages in thread
From: Tom @ 2010-12-15 12:55 UTC (permalink / raw)
  To: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 3156 bytes --]

I am about 2/3 way through the introduction to emacs lisp, and thought 
it would help my learning if I wrote tried writing a simple script to do 
something useful to me with the lessons I have covered so far so far.  I 
should point out I am surgeon not a computer scientist and know nothing 
more about programming than what is contained in the introduction to 
emacs lisp.
I end up with this:

(defun nirs-data-clean (number-of-channels)
"Cleans the output files from the INVOS monitor removing all columns 
apart from StO2 values, and the date and time stamps. Sto2 columns to be 
retained are specified by the NUMBER-OF-CHANNELS variable.  It assumes 
that channels are always used in numerical order, i.e. channel 1 always, 
then 2, then 3 then 4."
(interactive "nEnter number of channels (1-4): ")
(barf-if-buffer-read-only)
(require 'csv-mode)
(push-mark (point-max))
(goto-char (point-min))
(if (or (eq number-of-channels 1)
	(eq number-of-channels 2)
	(eq number-of-channels 3)
	(eq number-of-channels 4))
     (or (when (eq number-of-channels 1)
	  (csv-kill-fields '(4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 
23 24 25 26 27 28 29 30 31 32 33 34) (point) (mark)))
	(when (eq number-of-channels 2)
	  (csv-kill-fields '(4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 20 21 22 23 
24 25 26 27 28 29 30 31 32 33 34) (point) (mark)))
	(when (eq number-of-channels 3)
	  (csv-kill-fields '(4 5 6 7 8 9 11 12 13 14 15 16 18 19 20 21 22 23 24 
25 26 27 28 29 30 31 32 33 34) (point) (mark)))
	(when (eq number-of-channels 4)
	  (csv-kill-fields '(4 5 6 7 8 9 11 12 13 14 15 16 18 19 20 21 22 23 25 
26 27 28 29 30 31 32 33 34) (point) (mark))
	  (message "%s is not a valid number of channels.  Please enter a 
number between 1 and 4." number-of-channels))))
(when (y-or-n-p "Replace 0 StO$_2$ values with na: ")
     (progn (goto-char (point-min))
	   (while (re-search-forward "[^[:digit:]][0][^[:digit:]]" nil t)
	     (replace-match "na ")))))

The idea is to automatically clean unwanted columns from csv (space 
separated) data file and ask me if I want to replace 0 values with na. 
I appreciate this is very messy, and I should be able to specify ranges 
of field rather than listing every single one (but I couldn't get that 
to work), but it works kind of.  When I evaluate it and run it for the 
first time it works, but if I undo the changes to the file and run it 
again it often only takes out the 4th column, if I reopen the file or 
re-evaluate the script it usually works again but I can't seem to work 
the pattern of working and not working - as I can't see the pattern I 
can't learn where I am going wrong.

I have attached a small sample data file with 4 channels being used to 
illustrate the kind of file this is supposed to work on.

I assume I have made an obvious mistake but I don't have the experience 
to know what it is.  Any general comments about simple/better ways to 
clean this script would be welcome, for example would I be better making 
the regexp replace a yes/no arg to the function so if I call this script 
from another script I can specify a y/n argument (I don't know how to do 
this anyway though).

Tom

[-- Attachment #2: 101108N.R14 --]
[-- Type: text/plain, Size: 27398 bytes --]

08.11.10 14:57:17  67    0   4      -2.9254      -2.3866  0   0  72    0   4      -3.3003      -2.7971  0   0  63    0   4      -2.8989      -2.2108  0   0  75    0   4      -3.6963      -3.3294  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:57:24  69    0   4      -2.9621      -2.4101  0   0  73    0   4      -3.3033      -2.7983  0   0  63    0   4      -2.8936      -2.2066  0   0  75    0   4      -3.7303      -3.3724  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:57:30  69    0   4      -2.7329      -2.2557  0   0  74    0   4      -3.3159      -2.8015  0   0  63    0   4      -2.8896      -2.2074  0   0  76    0   4       -3.741      -3.3823  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:57:36  71    0   4      -2.9537      -2.4044  0   0  75    0   4      -3.3085      -2.8036  0   0  64    0   4      -2.8861      -2.2033  0   0  72    0   4       -3.676      -3.3543  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:57:43  73    0   4      -2.9509      -2.4047  0   0  76    0   4      -3.3151      -2.8131  0   0  65    0   4       -2.889      -2.2082  0   0  74    0   4      -3.7061      -3.3797  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:57:49  75    0   4      -2.9304      -2.3887  0   0  76    0   4      -3.3261      -2.8273  0   0  63    0   4      -2.8832       -2.208  0   0  74    0   4      -3.6884      -3.3698  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:57:55  74    0   4      -2.9003      -2.3646  0   0  75    0   4      -3.3277       -2.832  0   0  63    0   4      -2.8847      -2.2112  0   0  73    0   4      -3.6876      -3.3781  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:58:02  75    0   4      -2.8762       -2.348  0   0  74    0   4      -3.3355      -2.8432  0   0  62    0   4      -2.8635      -2.1954  0   0  72    0   4      -3.6862      -3.3857  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:58:08  72    0   4      -2.8286      -2.3068  0   0  74    0   4      -3.3396      -2.8499  0   0  61    0   4      -2.8588      -2.1947  0   0  73    0   4      -3.7164      -3.4112  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:58:15  71    0   4      -2.8161      -2.2968  0   0  73    0   4      -3.3412      -2.8519  0   0  59    0   4       -2.861      -2.1985  0   0  74    0   4      -3.7183      -3.4086  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:58:21  71    0   4      -2.8015      -2.2887  0   0  72    0   4       -3.338      -2.8518  0   0  58    0   4      -2.8703       -2.206  0   0  74    0   4      -3.7138      -3.4102  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:58:27  68    0   4      -2.8104      -2.2935  0   0  71    0   4      -3.3392      -2.8508  0   0  57    0   4      -2.8903      -2.2192  0   0  73    0   4      -3.6995      -3.3984  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:58:34  71    0   4      -2.8104      -2.2937  0   0  71    0   4      -3.3386      -2.8442  0   0  57    0   4      -2.9186      -2.2374  0   0  72    0   4      -3.6615      -3.3678  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:58:40  70    0   4       -2.817      -2.3025  0   0  72    0   4      -3.3677       -2.868  0   0  59    0   4      -2.9554      -2.2621  0   0  72    0   4      -3.6442      -3.3529  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:58:46  70    0   4      -2.8401      -2.3185  0   0  73    0   4      -3.3967      -2.8887  0   0  60    0   4      -2.9572      -2.2624  0   0  72    0   4      -3.6748      -3.3788  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:58:53  70    0   4      -2.8539      -2.3277  0   0  74    0   4      -3.4318      -2.9183  0   0  62    0   4       -2.966      -2.2697  0   0  74    0   4      -3.7079      -3.4021  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:58:59  73    0   4      -2.8681       -2.342  0   0  75    0   4      -3.4473       -2.934  0   0  64    0   4       -2.979      -2.2834  0   0  74    0   4      -3.7121      -3.4094  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:59:05  72    0   4      -2.8718      -2.3429  0   0  75    0   4      -3.4475      -2.9362  0   0  64    0   4      -2.9821      -2.2851  0   0  73    0   4      -3.7008      -3.4025  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:59:12  74    0   4      -2.8698      -2.3404  0   0  76    0   4      -3.4461       -2.936  0   0  65    0   4      -2.9665      -2.2722  0   0  73    0   4      -3.7019      -3.4011  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:59:18  74    0   4      -2.8557      -2.3283  0   0  77    0   4      -3.4366      -2.9295  0   0  65    0   4      -2.9637      -2.2709  0   0  73    0   4      -3.7009      -3.3997  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:59:24  73    0   4      -2.8321      -2.3101  0   0  77    0   4      -3.4126      -2.9116  0   0  66    0   4      -2.9569      -2.2671  0   0  73    0   4      -3.6999      -3.3974  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:59:31  73    0   4      -2.8171      -2.2951  0   0  76    0   4      -3.3806      -2.8819  0   0  65    0   4      -2.9406      -2.2551  0   0  72    0   4       -3.678      -3.3855  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:59:37  73    0   4      -2.8092      -2.2919  0   0  75    0   4      -3.3859      -2.8922  0   0  64    0   4      -2.9173      -2.2386  0   0  72    0   4       -3.687      -3.3922  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:59:43  74    0   4        -2.81      -2.2901  0   0  75    0   4      -3.3926      -2.8987  0   0  64    0   4      -2.9223      -2.2441  0   0  73    0   4      -3.7253      -3.4225  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:59:50  72    0   4      -2.7986      -2.2817  0   0  74    0   4      -3.3823      -2.8913  0   0  64    0   4      -2.9115      -2.2381  0   0  73    0   4      -3.6989      -3.4054  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 14:59:56  71    0   4      -2.8065      -2.2867  0   0  73    0   4       -3.387      -2.8981  0   0  63    0   4      -2.9005      -2.2308  0   0  73    0   4      -3.7087       -3.411  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:00:02  71    0   4      -2.8055      -2.2839  0   0  73    0   4      -3.3927      -2.9042  0   0  61    0   4      -2.9139      -2.2439  0   0  74    0   4      -3.7099       -3.412  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:00:09  70    0   4       -2.796      -2.2786  0   0  73    0   4       -3.368      -2.8866  0   0  61    0   4      -2.9006      -2.2343  0   0  73    0   4      -3.6826      -3.3921  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:00:15  70    0   4      -2.7993      -2.2791  0   0  72    0   4      -3.3751      -2.8883  0   0  60    0   4      -2.9171      -2.2468  0   0  73    0   4      -3.6917      -3.3943  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:00:21  69    0   4      -2.8031      -2.2811  0   0  71    0   4      -3.3907      -2.9039  0   0  60    0   4      -2.9495      -2.2707  0   0  74    0   4      -3.6977      -3.3957  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:00:28  70    0   4      -2.8014      -2.2789  0   0  71    0   4      -3.3965      -2.9056  0   0  61    0   4      -2.9823      -2.2931  0   0  73    0   4      -3.6989      -3.4004  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:00:34  69    0   4      -2.7876      -2.2692  0   0  71    0   4      -3.3769      -2.8892  0   0  62    0   4      -2.9697      -2.2819  0   0  74    0   4      -3.7139      -3.4126  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:00:40  69    0   4      -2.7855      -2.2673  0   0  70    0   4      -3.3676       -2.883  0   0  61    0   4      -2.9559      -2.2712  0   0  73    0   4      -3.7021      -3.4029  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:00:47  69    0   4      -2.7921       -2.272  0   0  70    0   4      -3.3812      -2.8929  0   0  61    0   4      -2.9581      -2.2734  0   0  74    0   4      -3.7249      -3.4155  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:00:53  69    0   4      -2.7993      -2.2779  0   0  70    0   4      -3.3923      -2.9034  0   0  61    0   4      -2.9675      -2.2804  0   0  73    0   4      -3.7236      -3.4236  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:01:00  70    0   4      -2.8125      -2.2892  0   0  70    0   4      -3.4108      -2.9178  0   0  62    0   4      -2.9788      -2.2895  0   0  73    0   4      -3.7241      -3.4223  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:01:06  71    0   4      -2.8267      -2.2996  0   0  70    0   4      -3.4234       -2.925  0   0  62    0   4      -2.9952      -2.3017  0   0  74    0   4       -3.722      -3.4167  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:01:12  71    0   4      -2.8285      -2.3022  0   0  71    0   4      -3.4175      -2.9155  0   0  63    0   4      -3.0016      -2.3052  0   0  74    0   4      -3.7148      -3.4108  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:01:18  72    0   4      -2.8268      -2.3017  0   0  72    0   4      -3.4242      -2.9218  0   0  64    0   4      -2.9955      -2.3018  0   0  73    0   4      -3.7007      -3.4105  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:01:25  73    0   4       -2.833      -2.3064  0   0  73    0   4      -3.4451      -2.9422  0   0  65    0   4      -3.0006      -2.3057  0   0  74    0   4      -3.7622      -3.4558  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:01:31  73    0   4      -2.8265      -2.3024  0   0  74    0   4      -3.4433      -2.9401  0   0  65    0   4      -2.9839      -2.2942  0   0  73    0   4       -3.733      -3.4329  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:01:38  73    0   4      -2.8262      -2.3024  0   0  74    0   4      -3.4426      -2.9414  0   0  65    0   4      -2.9788      -2.2908  0   0  73    0   4      -3.7269      -3.4354  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:01:44  74    0   4      -2.8333       -2.308  0   0  75    0   4      -3.4536        -2.95  0   0  66    0   4       -2.993      -2.3017  0   0  73    0   4      -3.7322      -3.4464  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:01:50  74    0   4      -2.8352      -2.3116  0   0  76    0   4      -3.4686      -2.9617  0   0  66    0   4      -2.9907      -2.3032  0   0  73    0   4      -3.7216      -3.4334  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:01:57  76    0   4       -2.867      -2.3394  0   0  76    0   4       -3.517      -2.9986  0   0  66    0   4      -3.0082      -2.3177  0   0  76    0   4      -3.8239      -3.5004  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:02:03  77    0   4      -2.8807      -2.3518  0   0  77    0   4      -3.5242      -3.0046  0   0  66    0   4       -2.997      -2.3068  0   0  75    0   4       -3.805       -3.488  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:02:09  76    0   4      -2.8714      -2.3445  0   0  79    0   4      -3.5094      -2.9927  0   0  66    0   4      -2.9912      -2.3018  0   0  77    0   4      -3.8063      -3.4905  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:02:16  77    0   4      -2.8658      -2.3384  0   0  80    0   4      -3.5121      -2.9965  0   0  66    0   4      -2.9822      -2.2941  0   0  76    0   4      -3.7856      -3.4762  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:02:22  77    0   4      -2.8531      -2.3304  0   0  80    0   4      -3.4822      -2.9729  0   0  66    0   4      -2.9765      -2.2891  0   0  75    0   4      -3.7534      -3.4513  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:02:28  80    0   4      -2.8507      -2.3285  0   0  80    0   4      -3.4815      -2.9765  0   0  65    0   4      -2.9793      -2.2907  0   0  75    0   4      -3.7587      -3.4546  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:02:35  77    0   4      -2.8512      -2.3275  0   0  81    0   4      -3.4948      -2.9887  0   0  65    0   4      -2.9979       -2.307  0   0  74    0   4      -3.7474      -3.4505  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:02:41  78    0   4      -2.8578      -2.3332  0   0  81    0   4      -3.5073      -2.9967  0   0  66    0   4      -3.0193      -2.3256  0   0  75    0   4      -3.7672      -3.4638  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:02:47  78    0   4      -2.8552       -2.332  0   0  80    0   4      -3.4992      -2.9906  0   0  66    0   4      -3.0192      -2.3244  0   0  75    0   4      -3.7629      -3.4565  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:02:54  78    0   4      -2.8521      -2.3279  0   0  80    0   4      -3.4981      -2.9897  0   0  66    0   4       -3.012      -2.3192  0   0  76    0   4      -3.7938      -3.4765  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:03:00  78    0   4      -2.8488      -2.3267  0   0  80    0   4      -3.5088      -3.0015  0   0  66    0   4      -3.0249      -2.3312  0   0  76    0   4      -3.8126       -3.499  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:03:06  77    0   4       -2.839      -2.3185  0   0  80    0   4      -3.5126      -3.0042  0   0  67    0   4      -3.0384       -2.344  0   0  75    0   4      -3.8222      -3.5062  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:03:13  77    0   4      -2.8165      -2.3005  0   0  79    0   4      -3.4722      -2.9619  0   0  67    0   4      -3.0358      -2.3424  0   0  75    0   4      -3.7906      -3.4794  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:03:19  76    0   4      -2.7944      -2.2828  0   0  78    0   4       -3.448      -2.9428  0   0  66    0   4      -3.0146      -2.3256  0   0  74    0   4      -3.7585       -3.457  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:03:25  76    0   4      -2.7678      -2.2613  0   0  77    0   4      -3.4121       -2.913  0   0  66    0   4       -3.006      -2.3196  0   0  74    0   4      -3.7452      -3.4483  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:03:32  75    0   4       -2.749      -2.2503  0   0  76    0   4      -3.3761      -2.8823  0   0  66    0   4      -2.9957      -2.3125  0   0  74    0   4      -3.7516      -3.4504  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:03:38  72    0   4      -2.7313       -2.239  0   0  75    0   4      -3.3506      -2.8579  0   0  65    0   4      -2.9932      -2.3109  0   0  74    0   4      -3.7322      -3.4373  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:03:44  72    0   4      -2.7263      -2.2338  0   0  73    0   4        -3.33      -2.8426  0   0  64    0   4      -2.9748      -2.2976  0   0  73    0   4      -3.6916      -3.4071  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:03:51  71    0   4      -2.7246      -2.2337  0   0  72    0   4      -3.3252      -2.8378  0   0  64    0   4      -2.9822      -2.3028  0   0  73    0   4       -3.711      -3.4185  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:03:57  69    0   4       -2.732      -2.2417  0   0  71    0   4      -3.3147      -2.8289  0   0  63    0   4      -2.9959      -2.3142  0   0  74    0   4      -3.7196      -3.4206  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:04:03  70    0   4      -2.7115      -2.2248  0   0  70    0   4      -3.3041      -2.8196  0   0  62    0   4      -2.9994      -2.3177  0   0  74    0   4      -3.7004      -3.4071  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:04:10  68    0   4      -2.7035      -2.2169  0   0  69    0   4      -3.2991      -2.8146  0   0  63    0   4      -3.0137      -2.3276  0   0  73    0   4      -3.6819      -3.3961  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:04:16  67    0   4      -2.7058      -2.2185  0   0  68    0   4      -3.3001      -2.8124  0   0  63    0   4      -3.0305      -2.3368  0   0  72    0   4      -3.6647      -3.3879  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:04:22  67    0   4      -2.7059      -2.2178  0   0  68    0   4      -3.3032      -2.8135  0   0  63    0   4      -3.0423      -2.3444  0   0  72    0   4      -3.6711      -3.3931  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:04:29  67    0   4      -2.7077      -2.2185  0   0  67    0   4      -3.3035      -2.8148  0   0  64    0   4      -3.0358      -2.3379  0   0  71    0   4      -3.6541      -3.3801  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:04:35  65    0   4      -2.7074        -2.22  0   0  66    0   4      -3.3047      -2.8166  0   0  64    0   4      -3.0249      -2.3291  0   0  71    0   4      -3.6373      -3.3706  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:04:42  66    0   4      -2.7237       -2.232  0   0  66    0   4       -3.323      -2.8318  0   0  64    0   4       -3.022      -2.3288  0   0  71    0   4      -3.6838      -3.4011  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:04:48  66    0   4      -2.7285      -2.2243  0   0  66    0   4      -3.3311      -2.8382  0   0  65    0   4      -3.0328      -2.3339  0   0  76    0   4      -3.9515      -3.6021  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:04:54  68    0   4      -2.7269      -2.2277  0   0  66    0   4      -3.3122      -2.8217  0   0  64    0   4      -3.0169      -2.3215  0   0  76    0   4      -3.8994      -3.5572  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:05:01  67    0   4      -2.7482      -2.2495  0   0  67    0   4       -3.328      -2.8278  0   0  66    0   4      -3.0327      -2.3359  0   0  73    0   4      -3.7202      -3.4457  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:05:07  68    0   4      -2.7579       -2.261  0   0  70    0   4       -3.337      -2.8318  0   0  67    0   4      -3.0739      -2.3621  0   0  71    0   4      -3.6748       -3.417  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:05:13  69    0   4      -2.7848      -2.2801  0   0  73    0   4      -3.3737      -2.8588  0   0  69    0   4      -3.0661      -2.3554  0   0  74    0   4       -3.712      -3.4437  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:05:20  73    0   4      -2.8103      -2.2996  0   0  77    0   4      -3.4046      -2.8849  0   0  70    0   4      -3.0692      -2.3571  0   0  74    0   4      -3.7271      -3.4499  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:05:26  75    0   4      -2.8201      -2.3067  0   0  79    0   4      -3.4242      -2.9043  0   0  70    0   4      -3.0688      -2.3574  0   0  74    0   4      -3.7441      -3.4658  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:05:32  77    0   4      -2.8243      -2.3095  0   0  81    0   4      -3.4208      -2.9058  0   0  71    0   4       -3.058      -2.3496  0   0  72    0   4      -3.7145      -3.4531  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:05:39  81    0   4      -2.8334      -2.3152  0   0  82    0   4       -3.438      -2.9207  0   0  72    0   4      -3.0547      -2.3474  0   0  72    0   4        -3.73       -3.467  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:05:45  81    0   4       -2.854      -2.3343  0   0  83    0   4      -3.4822      -2.9582  0   0  72    0   4      -3.0744       -2.364  0   0  74    0   4       -3.804      -3.5254  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:05:51  82    0   4      -2.8865      -2.3644  0   0  85    0   4      -3.5113      -2.9838  0   0  72    0   4      -3.0894      -2.3756  0   0  75    0   4      -3.8412      -3.5541  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:05:58  82    0   4      -2.8793      -2.3573  0   0  85    0   4      -3.4824      -2.9606  0   0  72    0   4      -3.0826      -2.3676  0   0  76    0   4      -3.8193      -3.5384  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:06:04  83    0   4      -2.8621      -2.3474  0   0  85    0   4      -3.4784      -2.9607  0   0  73    0   4      -3.0871      -2.3709  0   0  75    0   4       -3.784      -3.5124  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:06:10  84    0   4      -2.8574      -2.3415  0   0  86    0   4      -3.4637      -2.9494  0   0  73    0   4      -3.0875      -2.3702  0   0  74    0   4      -3.7445      -3.4836  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:06:17  83    0   4      -2.8568      -2.3419  0   0  86    0   4      -3.4567      -2.9464  0   0  74    0   4        -3.08      -2.3655  0   0  73    0   4       -3.752      -3.4947  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:06:23  85    0   4      -2.8639      -2.3426  0   0  85    0   4      -3.4748       -2.965  0   0  75    0   4      -3.0878      -2.3731  0   0  73    0   4      -3.7552      -3.4926  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:06:29  84    0   4       -2.856       -2.338  0   0  85    0   4      -3.4622      -2.9551  0   0  75    0   4      -3.0751      -2.3645  0   0  75    0   4      -3.7609      -3.4949  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:06:36  83    0   4      -2.8478      -2.3303  0   0  85    0   4      -3.4483      -2.9435  0   0  74    0   4      -3.0448      -2.3422  0   0  73    0   4       -3.732      -3.4745  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:06:42  84    0   4       -2.838       -2.324  0   0  85    0   4      -3.4309      -2.9315  0   0  74    0   4      -3.0282      -2.3314  0   0  72    0   4      -3.7028      -3.4541  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:06:48  83    0   4      -2.8276      -2.3164  0   0  84    0   4      -3.4256      -2.9283  0   0  73    0   4      -3.0364      -2.3386  0   0  73    0   4      -3.7484      -3.4783  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:06:55  84    0   4      -2.8139      -2.3057  0   0  83    0   4      -3.4184      -2.9204  0   0  73    0   4      -3.0546      -2.3558  0   0  73    0   4      -3.7393      -3.4766  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:07:01  84    0   4      -2.7963      -2.2897  0   0  83    0   4      -3.3893      -2.8932  0   0  72    0   4      -3.0602      -2.3621  0   0  73    0   4      -3.7206      -3.4646  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:07:07  82    0   4      -2.7732      -2.2755  0   0  83    0   4      -3.3737      -2.8811  0   0  72    0   4      -3.0539      -2.3574  0   0  72    0   4      -3.7042      -3.4524  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:07:14  81    0   4      -2.7745      -2.2763  0   0  82    0   4      -3.3704      -2.8803  0   0  71    0   4      -3.0538      -2.3564  0   0  74    0   4      -3.7182      -3.4671  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:07:20  82    0   4      -2.7662      -2.2729  0   0  81    0   4       -3.357      -2.8732  0   0  70    0   4      -3.0324      -2.3406  0   0  72    0   4      -3.6973      -3.4541  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:07:27  77    0   4      -2.7668      -2.2728  0   0  80    0   4      -3.3588      -2.8771  0   0  70    0   4      -3.0329      -2.3425  0   0  72    0   4      -3.6937      -3.4567  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:07:33  77    0   4      -2.7669      -2.2747  0   0  79    0   4      -3.3547      -2.8753  0   0  70    0   4      -3.0241      -2.3367  0   0  71    0   4      -3.6833      -3.4457  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:07:39  78    0   4      -2.7652      -2.2716  0   0  79    0   4      -3.3565      -2.8773  0   0  68    0   4      -3.0339      -2.3445  0   0  73    0   4      -3.6956      -3.4433  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:07:45  79    0   4      -2.7775      -2.2818  0   0  78    0   4      -3.3635      -2.8825  0   0  68    0   4       -3.019      -2.3331  0   0  74    0   4      -3.7409      -3.4826  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:07:52  78    0   4      -2.7902        -2.29  0   0  78    0   4       -3.379      -2.8932  0   0  68    0   4      -3.0668      -2.3628  0   0  75    0   4      -3.7425      -3.4794  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:07:58  77    0   4      -2.7842      -2.2863  0   0  77    0   4      -3.3449      -2.8618  0   0  69    0   4      -3.0753      -2.3669  0   0  74    0   4      -3.7178      -3.4592  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0
08.11.10 15:08:05  78    0   4      -2.7882      -2.2909  0   0  76    0   4      -3.3442       -2.858  0   0  70    0   4      -3.0893      -2.3769  0   0  75    0   4      -3.7027      -3.4443  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: simple first emacs script
  2010-12-15 12:55 simple first emacs script Tom
@ 2010-12-15 14:51 ` Pascal J. Bourguignon
  2010-12-15 17:28   ` Tom
  0 siblings, 1 reply; 7+ messages in thread
From: Pascal J. Bourguignon @ 2010-12-15 14:51 UTC (permalink / raw)
  To: help-gnu-emacs

Tom <tom@somewhere.com> writes:

> I am about 2/3 way through the introduction to emacs lisp, and thought
> it would help my learning if I wrote tried writing a simple script to
> do something useful to me with the lessons I have covered so far so
> far.  I should point out I am surgeon not a computer scientist and
> know nothing more about programming than what is contained in the
> introduction to emacs lisp.
> I end up with this:
>
> (defun nirs-data-clean (number-of-channels)
> "Cleans the output files from the INVOS monitor removing all columns
> apart from StO2 values, and the date and time stamps. Sto2 columns to
> be retained are specified by the NUMBER-OF-CHANNELS variable.  It
> assumes that channels are always used in numerical order, i.e. channel
> 1 always, then 2, then 3 then 4."
> (interactive "nEnter number of channels (1-4): ")
[...]

First, unless the indenting was destroyed by your newsreader program,
you might want to make use of the indent-region command ( type C-M-\ )  
so that your source will look like:


(defun nirs-data-clean (number-of-channels)
  "Cleans the output files from the INVOS monitor removing all columns
apart from StO2 values, and the date and time stamps. Sto2 columns to
be retained are specified by the NUMBER-OF-CHANNELS variable.  It
assumes that channels are always used in numerical order, i.e. channel
1 always, then 2, then 3 then 4."
  (interactive "nEnter number of channels (1-4): ")
  (barf-if-buffer-read-only)
  (require 'csv-mode)
  (push-mark (point-max))
  (goto-char (point-min))
  (if (or (eq number-of-channels 1)
          (eq number-of-channels 2)
          (eq number-of-channels 3)
          (eq number-of-channels 4))
      (or (when (eq number-of-channels 1)
            (csv-kill-fields '(4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
                               21 22 23 24 25 26 27 28 29 30 31 32 33 34) (point) (mark)))
          (when (eq number-of-channels 2)
            (csv-kill-fields '(4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 20 21
                               22 23 24 25 26 27 28 29 30 31 32 33 34) (point) (mark)))
          (when (eq number-of-channels 3)
            (csv-kill-fields '(4 5 6 7 8 9 11 12 13 14 15 16 18 19 20 21 22
                               23 24 25 26 27 28 29 30 31 32 33 34) (point) (mark)))
          (when (eq number-of-channels 4)
            (csv-kill-fields '(4 5 6 7 8 9 11 12 13 14 15 16 18 19 20 21 22
                               23 25 26 27 28 29 30 31 32 33 34) (point) (mark))
            (message "%s is not a valid number of channels.  Please enter a
number between 1 and 4." number-of-channels))))
  (when (y-or-n-p "Replace 0 StO$_2$ values with na: ")
    (progn (goto-char (point-min))
           (while (re-search-forward "[^[:digit:]][0][^[:digit:]]" nil t)
             (replace-match "na ")))))

Instead of calling barf-if-buffer-read-only, you can just prefix the
interactive string with a star:

    (interactive "*nEnter number of channels (1-4): ")

The (require 'csv-mode) form would be better placed on the toplevel
(ie. above the defun form).


Instead of push-mark (I don't see the matching pop-mark), you might use
the save-excursion macro.

Instead of using eq, you might prefer to use eql by default.  In the
case of numbers, it would be better to use =.

Instead of:
    
    (or (when ... ...)
        (when ... ...)
        ...)

you can write:

    (cond (... ...)
          (... ...)
          ...)

And since all your conditions are about the same variable, matching a
set of value comparable with eql, you could instead use case:

    (case number-of-channels
      ((1)  ...)
      ((2)  ...)
      ((3)  ...)
      ((4)  ...)
      (otherwise (error ...)))

Notice how the indentation shows that your message form is not placed at
the right level.  You intended it to be the else branch of the if form,
but you put it inside the last when body.  Also you probably want to use
error here instead of message, since if the number of channel is wrong,
you probably don't want to replace the StO2 zeroes.


    You may want to use paredit, which helps editing lisp code in a
    structural way.

    http://www.emacswiki.org/ParEdit
    http://www.emacswiki.org/emacs/PareditCheatsheet
    http://mumble.net/~campbell/emacs/paredit.el

    Just download this paredit.el file,  and put it in

      /usr/share/emacs/site-lisp/

    (check that this path is in load-path, typing C-h v load-path RET.  If
    it is not there, then use the path of the site-lisp directory listed in
    load-path),

    then put:

       (require 'cl)
       (require 'paredit)
       (push 'paredit-mode emacs-lisp-mode-hook)
       (push 'paredit-mode       lisp-mode-hook)

    in your ~/.emacs file.

    If you want to activate immediately, without restarting emacs, you may
    reload ~/.emacs with M-x load-file RET ~/.emacs RET


Finally, since the bodies of each case branch are the same, you may
distribute it around and write:

    (csv-kill-fields (case number-of-channels
                             ((1) '(4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34))
                             ((2) '(4 5 6 7 8 9    11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34))
                             ((3) '(4 5 6 7 8 9    11 12 13 14 15 16    18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34))
                             ((4) '(4 5 6 7 8 9    11 12 13 14 15 16    18 19 20 21 22 23    25 26 27 28 29 30 31 32 33 34))
                             (otherwise
                              (message "%s is not a valid number of channels.  Please enter a number between 1 and 4."
                                       number-of-channels)))
                           start end)

But then, it might be clearer to give an intensional definition instead
of an extensional one.  A practical operator would be iota:

    (defun iota (count &optional start step)
      "
    RETURN:   A list containing the elements 
              (start start+step ... start+(count-1)*step)
              The start and step parameters default to 0 and 1, respectively. 
              This procedure takes its name from the APL primitive.
    EXAMPLES: (iota 5) => (0 1 2 3 4)
              (iota 5 0 -0.1) => (0 -0.1 -0.2 -0.3 -0.4)
    "
      (setf start (or start 0) step (or step 1))
      (when (< 0 count)
        (do ((result '())
             (item (+ start (* step (1- count))) (- item step)))
            ((< item start) result)
          (push item result))))


So you could write:

    (csv-kill-fields (set-difference (iota 34 1)
                                     (ecase number-of-channels
                                       ((1) '(1 2 3))
                                       ((2) '(1 2 3 10))
                                       ((3) '(1 2 3 10 17))
                                       ((4) '(1 2 3 10 17 24))))
                     (point-min) (point-max))

We may remove the otherwise branch, assuming we only get correct
number-of-channels (and using ecase instead of case to signal an error
if not), which we can ensure by using a more sophisticated interactive
form, using competing-read:

    (interactive
       (list
        (first (read-from-string
                (completing-read "Enter number of channels (1-4): "
                                 (mapcar (lambda (x) (cons (format "%d" x) nil)) (iota 4 1))
                                 (function identity)
                                 t                 ; require match
                                 "" nil "1" nil)))))
    (barf-if-buffer-read-only) ; in this case, we need to call it
                               ; separately. 


Be sure to read the documentation of each operator used, eg. with:
    C-h f interactive RET 
    C-h f completing-read RET 
etc.




when (and unless and other macros) has an implicit progn, so there's no
need to embed one in it.



So to wrap it up so far, you could have:


    (defun nirs-data-clean (number-of-channels)
      "Cleans the output files from the INVOS monitor removing all columns
    apart from StO2 values, and the date and time stamps. Sto2 columns to
    be retained are specified by the NUMBER-OF-CHANNELS variable.  It
    assumes that channels are always used in numerical order, i.e. channel
    1 always, then 2, then 3 then 4."
      (interactive
       (list
        (first (read-from-string
                (completing-read "Enter number of channels (1-4): "
                                 (mapcar (lambda (x) (cons (format "%d" x) nil)) (iota 4 1))
                                 (function identity)
                                 t                 ; require match
                                 "" nil "1" nil)))))
      (barf-if-buffer-read-only)
      (save-excursion
        (let ((start (point-min))
              (end   (point-max)))
          (goto-char start)
          (csv-kill-fields (set-difference (iota 34 1)
                                           (ecase number-of-channels
                                             ((1) '(1 2 3))
                                             ((2) '(1 2 3 10))
                                             ((3) '(1 2 3 10 17))
                                             ((4) '(1 2 3 10 17 24))))
                           start end)
          (when (y-or-n-p "Replace 0 StO$_2$ values with na: ")
            (goto-char start)
            (while (re-search-forward "[^[:digit:]][0][^[:digit:]]" nil t)
              (replace-match "na "))))))



> The idea is to automatically clean unwanted columns from csv (space
> separated) data file and ask me if I want to replace 0 values with
> na. 


Ah, if you read the documentation of csv-kill-fields,  you will see that
it depends on the right setting of the variable csv-separators to know
what separator to use.  By default I have it set to a comma.  So you
want to bind this variable in your function:

    (let ((csv-separators '(" ")))
      (csv-kill-fields ...))

Note however that it is a single character string, and that your fields
are separated by several.  When I try it, it fails with csv-kill-fields
complaining about the number of columns.  It is probably better to use
commas to separate the fields, so:

    (defun nirs-data-clean (number-of-channels)
      "Cleans the output files from the INVOS monitor removing all columns
    apart from StO2 values, and the date and time stamps. Sto2 columns to
    be retained are specified by the NUMBER-OF-CHANNELS variable.  It
    assumes that channels are always used in numerical order, i.e. channel
    1 always, then 2, then 3 then 4."
      (interactive
       (list
        (first (read-from-string
                (completing-read "Enter number of channels (1-4): "
                                 (mapcar (lambda (x) (cons (format "%d" x) nil)) (iota 4 1))
                                 (function identity)
                                 t                 ; require match
                                 "" nil "1" nil)))))
      (barf-if-buffer-read-only)
      (save-excursion
        (replace-regexp " +" "," nil (point-min) (point-max))
        (goto-char (point-min))
        (let ((csv-separators '(",")))
          (csv-kill-fields (set-difference (iota 34 1)
                                           (ecase number-of-channels
                                             ((1) '(1 2 3))
                                             ((2) '(1 2 3 10))
                                             ((3) '(1 2 3 10 17))
                                             ((4) '(1 2 3 10 17 24))))
                           (point-min) (point-max)))
        (when (y-or-n-p "Replace 0 StO$_2$ values with na: ")
          (goto-char (point-min))
          (while (re-search-forward "[^[:digit:]]0[^[:digit:]]" nil t)
            (replace-match "na ")))
        ;; let's put back spaces as separators:
        (replace-regexp "," " " nil (point-min) (point-max))))


> I appreciate this is very messy, and I should be able to specify
> ranges of field rather than listing every single one (but I couldn't
> get that to work), but it works kind of.  When I evaluate it and run
> it for the first time it works, but if I undo the changes to the file
> and run it again it often only takes out the 4th column, if I reopen
> the file or re-evaluate the script it usually works again but I can't
> seem to work the pattern of working and not working - as I can't see
> the pattern I can't learn where I am going wrong.

I see no reason why that would happen.  In any case, my version seems to
work correctly, even after undoing and running it again.

> I assume I have made an obvious mistake but I don't have the
> experience to know what it is.  Any general comments about
> simple/better ways to clean this script would be welcome, for example
> would I be better making the regexp replace a yes/no arg to the
> function so if I call this script from another script I can specify a
> y/n argument (I don't know how to do this anyway though).

Indeed, this is a good intension.  You can separate interactive user
interface commands from the functions doing the actual work, so that you
can reuse the later.  The interactive form allow you to merge both
usages.

You only have to add the wanted parameter, and specify it in the
interactive form.  You can also specify some parameters optional:


    (defun nirs-data-clean (number-of-channels &optional replace-StO2-0-p)
       ...)

The simple interactive form would use a multiline string:

      (interactive "*nEnter number of channels (1-4):
sReplace 0 StO$_2$ values with na (y/n): ")

Unfortunately, interactive doesn't provide for a 'boolean' input, so
we'll keep using the sophisticated form:

    (defun nirs-data-clean (number-of-channels &optional replace-StO2-0-p)
      "Cleans the output files from the INVOS monitor removing all columns
    apart from StO2 values, and the date and time stamps. Sto2 columns to
    be retained are specified by the NUMBER-OF-CHANNELS variable.  It
    assumes that channels are always used in numerical order, i.e. channel
    1 always, then 2, then 3 then 4."
      (interactive
       (list
        (first (read-from-string
                (completing-read "Enter number of channels (1-4): "
                                 (mapcar (lambda (x) (cons (format "%d" x) nil)) (iota 4 1))
                                 (function identity)
                                 t                 ; require match
                                 "" nil "1" nil)))

        (string= "yes"
                 (completing-read "Replace 0 StO$_2$ values with na: "
                                  (mapcar (lambda (x) (cons x nil)) '("yes" "no"))
                                  (function identity)
                                  t                 ; require match
                                  "" nil "yes" nil))))
      (barf-if-buffer-read-only)
      (save-excursion
        (replace-regexp " +" "," nil (point-min) (point-max))
        (goto-char (point-min))
        (let ((csv-separators '(",")))
          (csv-kill-fields (set-difference (iota 34 1)
                                           (ecase number-of-channels
                                             ((1) '(1 2 3))
                                             ((2) '(1 2 3 10))
                                             ((3) '(1 2 3 10 17))
                                             ((4) '(1 2 3 10 17 24))))
                           (point-min) (point-max)))
        (when replace-StO2-0-p
          (goto-char (point-min))
          (while (re-search-forward "[^[:digit:]]0[^[:digit:]]" nil t)
            (replace-match "na ")))
        ;; let's put back spaces as separators:
        (replace-regexp "," " " nil (point-min) (point-max))))




Finally, when you'll have completed the "Introduction to Emacs Lisp", I
would advise you to read SICP.

SICP   = Structure and Interpretation of Computer Programs
         http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-4.html
         http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/
         http://www.codepoetics.com/wiki/index.php?title=Topics:SICP_in_other_languages
         http://eli.thegreenplace.net/category/programming/lisp/sicp/
         http://www.neilvandyke.org/sicp-plt/
         http://www.youtube.com/watch?v=rdj6deraQ6k

(and watch the videos, they're quite instructive).  

While this book uses scheme, it's subject matter is not about scheme,
but programming in general, as can be seen from the translations of the
exercises in other programming languages (well, it seems the wiki has
been defaced, so it's not available hopefully temporarily, but eli's
blog contains Common Lisp versions of the exercises, which are close to
emacs lisp).


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: simple first emacs script
  2010-12-15 14:51 ` Pascal J. Bourguignon
@ 2010-12-15 17:28   ` Tom
  2010-12-15 18:37     ` Pascal J. Bourguignon
  0 siblings, 1 reply; 7+ messages in thread
From: Tom @ 2010-12-15 17:28 UTC (permalink / raw)
  To: help-gnu-emacs

Wow Pascal that is quite an amazing response thanks.

You introduced several new things I don't know about so I can't comment 
on them until I go away and learn them but in response to what I do 
understand.

Yes the indentation was destroyed by newsreader, but thanks for pointing 
me to paredit as I was finding managing parenthesis a pain.

> The (require 'csv-mode) form would be better placed on the toplevel
> (ie. above the defun form).

I don't get this.  If I understand you correctly you are suggesting 
something like this:
(require 'csv-mode)
(defun ...
           )

If I do this then wont the require mode cease to be part of the 
functions definition.  Normally it would not be required to set the mode 
the csv as the file extension would be .csv and csv-mode is called 
automatically, but the raw files I receive have random extensions - I 
suppose I could rename them all to overcome this but it seemed simpler 
to tell the function to go into csv mode otherwise it tries to process 
the file in fundamental mode.


> Instead of push-mark (I don't see the matching pop-mark), you might use
> the save-excursion macro.

I did actually start with save-excursion but I have no interest in 
saving the point the mark, the whole point of pushing the mark and 
moving the point to the start of the buffer was to specify the region 
arguments in csv-kill-fields, i.e.
(csv-kill-fields '(4 ...) (point) (mark))

I guess this might be more logically done with
(csv-kill-fields '(4 ...) (point-min) (point-max))
would that be considered better form?

Thanks for the advice on eql cond, case, and distribution of my column 
specifiers that will clean things up a bit.  I don't know enough to 
follow your iota operator but that gives me something to work towards

> when (and unless and other macros) has an implicit progn, so there's no
> need to embed one in it.

That is handy to know.

> Ah, if you read the documentation of csv-kill-fields,  you will see that
> it depends on the right setting of the variable csv-separators to know
> what separator to use.  By default I have it set to a comma.  So you
> want to bind this variable in your function:
>
>      (let ((csv-separators '(" ")))
>        (csv-kill-fields ...))
> Note however that it is a single character string, and that your fields
> are separated by several.  When I try it, it fails with csv-kill-fields
> complaining about the number of columns.  It is probably better to use
> commas to separate the fields, ...

I have read the documentation (that doesn't mean I understood it 
though).  I have the csv separators specified in my .emacs file (it seem 
it will accept both " " and "," so csv-modes seems to read my files 
correctly.  But I guess it is logical to specify these in the function 
in case I run it on a computer without these specified.  I don't seem to 
get problems  with csv-kill-fields complaining about number of columns 
but maybe I have just worked through it with trial and error and no real 
understanding.

> Indeed, this is a good intension.  You can separate interactive user
> interface commands from the functions doing the actual work, so that you
> can reuse the later.  The interactive form allow you to merge both
> usages.
>
> You only have to add the wanted parameter, and specify it in the
> interactive form.  You can also specify some parameters optional:
>
>
>      (defun nirs-data-clean (number-of-channels&optional replace-StO2-0-p)
>         ...)
>
> The simple interactive form would use a multiline string:
>
>        (interactive "*nEnter number of channels (1-4):
> sReplace 0 StO$_2$ values with na (y/n): ")
>
> Unfortunately, interactive doesn't provide for a 'boolean' input, so
> we'll keep using the sophisticated form:

When I said I can't do this I was looking to specify boolean input, good 
to know I shouldn't waste my time looking for it.  I could have probably 
worked it out the way you showed but it would have probably taken me a 
few hours of testing so thanks for demonstrating that.

Your final script seems more solid than mine, as in it behaves in the 
same way on either iteration even after undoing.  It doesn't seem to 
work perfectly with across all channel options in some of the files I 
ran it one, but there are lots of ideas in there (such as temporarily 
using commas) for me to incorporate into my script so thanks again.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: simple first emacs script
  2010-12-15 17:28   ` Tom
@ 2010-12-15 18:37     ` Pascal J. Bourguignon
  2010-12-16 15:21       ` Tom
  2010-12-16 21:55       ` Stefan Monnier
  0 siblings, 2 replies; 7+ messages in thread
From: Pascal J. Bourguignon @ 2010-12-15 18:37 UTC (permalink / raw)
  To: help-gnu-emacs

Tom <tom@somewhere.com> writes:

> Wow Pascal that is quite an amazing response thanks.
>
> You introduced several new things I don't know about so I can't
> comment on them until I go away and learn them but in response to what
> I do understand.
>
> Yes the indentation was destroyed by newsreader, but thanks for
> pointing me to paredit as I was finding managing parenthesis a pain.
>
>> The (require 'csv-mode) form would be better placed on the toplevel
>> (ie. above the defun form).
>
> I don't get this.  If I understand you correctly you are suggesting
> something like this:
> (require 'csv-mode)
> (defun ...
>           )
>
> If I do this then wont the require mode cease to be part of the
> functions definition.  Normally it would not be required to set the
> mode the csv as the file extension would be .csv and csv-mode is
> called automatically, but the raw files I receive have random
> extensions - I suppose I could rename them all to overcome this but it
> seemed simpler to tell the function to go into csv mode otherwise it
> tries to process the file in fundamental mode.

require only loads a library (if it is not already loaded).  Setting a
mode for a buffer would be done by calling the specific mode command,
which may be defined in a library:  (csv-mode)

(By the way, these commands, as well as a lot of rarely commands, may be
not loaded initially, but defined as autoloaded functions, that will
load the library that contains their real definition automatically the
first time they're called.  For example, if you start emacs again,
before loading csv-mode.el, the documentation of the command csv-mode
(C-x f csv-mode RET) is:

    csv-mode is an interactive autoloaded Lisp function in `csv-mode.el'.

    [Arg list not available until function definition is loaded.]

    Major mode for editing comma-separated value files.
)

Loading csv-mode with (require 'csv-mode) doesn't change the mode of the
buffer, and this doesn't prevent csv-kill-fields to work, even if the
mode of the buffer is not csv-mode.  In general, modes only establish
the key bindings and font-lock keywords to help editing a specific kind
of text, but all the commands are applyable in all the modes.  There may
be some special modes that do some behind the scene processing
(eg. building data structures in parallel to the buffer, defining
buffer-local variables) that would be required by some of their commands
for them to work, but it's rather rare. 


But, I would advise to avoid changing the mode of the buffer in a
command such as nirs-data-clean.  If you want to open the .R14 files in
the CSV mode, you can do it by adding an entry to the auto-mode-alist
variable (C-h v auto-mode-alist RET) in ~/.emacs:

    (push '("\\.R14$" . csv-mode) auto-mode-alist)

However, the R14 example file you gave is not a CSV formated file. 
See below.


>> Instead of push-mark (I don't see the matching pop-mark), you might use
>> the save-excursion macro.
>
> I did actually start with save-excursion but I have no interest in
> saving the point the mark, the whole point of pushing the mark and
> moving the point to the start of the buffer was to specify the region
> arguments in csv-kill-fields, i.e.
> (csv-kill-fields '(4 ...) (point) (mark))
>
> I guess this might be more logically done with
> (csv-kill-fields '(4 ...) (point-min) (point-max))
> would that be considered better form?

Yes, I noticed later your use of the (point) and (mark).  But indeed, if
you follow the documentation of push-mark, you'll see in the
documentation of set-mark that this mechanism is reserved to the user
interactive use, and that commands should avoid tampering with it.

At first, I kept (point-min) and (point-max) in local variables start
and end, but since I added the replacement of spaces by comma, this
changed the size of the buffer, and therefore the value of (point-max).
Therefore I called these functions everytime.

If you want to memorize a buffer position in the course of editing that
may change its absolute position (insertion and deletions), you may use
markers (see the functions make-marker and set-marker), but markers need
to be 'freed' explicitely by reseting them to nil, so they're less
convenient to use than just calling (point-max) again (but to keep a
position in the middle of the buffer they'd be the right mechanism to
use).


>> Ah, if you read the documentation of csv-kill-fields,  you will see that
>> it depends on the right setting of the variable csv-separators to know
>> what separator to use.  By default I have it set to a comma.  So you
>> want to bind this variable in your function:
>>
>>      (let ((csv-separators '(" ")))
>>        (csv-kill-fields ...))
>> Note however that it is a single character string, and that your fields
>> are separated by several.  When I try it, it fails with csv-kill-fields
>> complaining about the number of columns.  It is probably better to use
>> commas to separate the fields, ...
>
> I have read the documentation (that doesn't mean I understood it
> though).  I have the csv separators specified in my .emacs file (it
> seem it will accept both " " and "," so csv-modes seems to read my
> files correctly.  

Well, I'm not sure if it's a good idea to have both in the
csv-separators list.  One would have to check how csv functions deal
with csv-separators.  For example, I wonder what would happen if a
record contained both separators:

     data item,other data, item

It this ("data" "item,other" "data," "item")
or      ("data item"  "other data" " item")
or      ("data" "item" "other" "data" "item") 
?



> But I guess it is logical to specify these in the
> function in case I run it on a computer without these specified.  I
> don't seem to get problems  with csv-kill-fields complaining about
> number of columns but maybe I have just worked through it with trial
> and error and no real understanding.

I was surprised by this result too, given my reading of the
documentation of csv-kill-fields.



> Your final script seems more solid than mine, as in it behaves in the
> same way on either iteration even after undoing.  It doesn't seem to
> work perfectly with across all channel options in some of the files I
> ran it one, but there are lots of ideas in there (such as temporarily
> using commas) for me to incorporate into my script so thanks again.

Perhaps the problem comes from the fact that the files don't look like
csv files really.  They seem to have fixed-width columns, filled with
spaces.  In a csv file, if the separator character is present
consecutively, that would mean that there is an empty field in between.
Aligning data with a variable number of spaces is therefore
incompatible.

Perhaps some of your files have fields with spaces in the middle, or
empty fields.  Then simply replacing sequences of spaces by comma to
make it csv (or have csv function interpret the space as a field
separator) will make the csv function interpret incorrectly the fields.

I would advise to check the specifications of the file format, and
perhaps use a different code to convert it to csv.  For example,
assuming we have just records of fixed-width fields.

(defun spacep (ch)  (= ch ?\ )) ; one space character.


(let ((one-record "08.11.10 14:57:17  67    0   4      -2.9254      -2.3866  0   0  72    0   4      -3.3003      -2.7971  0   0  63    0   4      -2.8989      -2.2108  0   0  75    0   4      -3.6963      -3.3294  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0"))
 
  (loop ; let's detect a data -> space transition
    with data = nil
    with fields = '()
    for pos from 0
    for ch across one-record
    do (if data
         (when (spacep ch)
           (setf data nil)
           (push pos fields))
         (unless (spacep ch)
           (setf data t)))
    finally (return (cons 0 (reverse (cons (length one-record) fields))))))

--> (0 8 17 21 26 30 43 56 59 63 67 72 76 89 102 105 109 113 118 122 135 148 151 155 159 164 168 181 194 197 201 217 233 249 265)


So you could now split the record in fields, remove the spaces, and
concatenate it back into a csv record:




(defvar *r14-field-positions* 
        '(0 8 17 21 26 30 43 56 59 63 67 72 76 89 102 105 109 113 118
          122 135 148 151 155 159 164 168 181 194 197 201 217 233 249
          265)) 

(defun csvify-r14-record (record)
  (unsplit-string 
     (mapcar
        (lambda (field) ; if the field contains a comma, 
                        ; it needs to be quoted.
           (if (find ?, field)
              (concat "\"" 
                      (replace-regexp-in-string  "\"" "\\\""  field)
                      "\"")
              field))
        (loop
          for (start end) on *r14-field-positions*
          while end
          collect (string-trim " " (subseq record start end))))
      ","))



(let ((one-record "08.11.10 14:57:17  67    0   4      -2.9254      -2.3866  0   0  72    0   4      -3.3003      -2.7971  0   0  63    0   4      -2.8989      -2.2108  0   0  75    0   4      -3.6963      -3.3294  0   0  AB0912040885-0  AB0912040757-0  AB0912040628-0  AB0912040780-0"))

   (csvify-r14-record one-record))
--> "08.11.10,14:57:17,67,0,4,-2.9254,-2.3866,0,0,72,0,4,-3.3003,-2.7971,0,0,63,0,4,-2.8989,-2.2108,0,0,75,0,4,-3.6963,-3.3294,0,0,AB0912040885-0,AB0912040757-0,AB0912040628-0,AB0912040780-0"


So now we only have to call this function on each line of the buffer:


(defun csvify-r14-buffer ()
  (interactive)
  (dolines (start-line end-line)
     (let ((new-record (csvify-r14-record (buffer-substring start-line end-line))))
       (delete-region start-line end-line)
       (insert new-record))))



With the following functions and macro (from my personal library):


(defun string-trim (character-bag string-designator)
  "Common-Lisp: returns a substring of string, with all characters in \
character-bag stripped off the beginning and end.
"
  (unless (sequencep character-bag)
    (signal 'type-error  "Expected a sequence for `character-bag'."))
  (let* ((string (string* string-designator))
         (margin (format "[%s]*" (regexp-quote
                                  (if (stringp character-bag)
                                      character-bag
                                      (map 'string 'identity character-bag)))))
         (trimer (format "\\`%s\\(\\(.\\|\n\\)*?\\)%s\\'" margin margin)))
    (replace-regexp-in-string  trimer "\\1" string)))


(defun unsplit-string (string-list &rest separator)
  "Does the inverse than split-string. If no separator is provided 
then a simple space is used."
  (if (null separator)
      (setq separator " ")
      (if (= 1 (length separator))
          (setq separator (car separator))
          (error "unsplit-string: Too many separator arguments.")))
  (if (not (char-or-string-p separator))
      (error "unsplit-string: separator must be a string or a char."))
  (apply 'concat (list-insert-separator string-list separator)))
       

(defmacro* with-marker ((var position) &body body)
  (let ((vposition (gensym))) ; so (eq var position) still works.
    `(let* ((,vposition ,position)
            (,var (make-marker)))
       (set-marker ,var ,vposition)
       (unwind-protect (progn ,@body)
         (set-marker ,var nil)))))


(defmacro* dolines (start-end &body body)
  "Executes the body with start-var and end-var bound to the start \
and the end of each lines of the current buffer in turn."
  (let ((vline (gensym)))
    (destructuring-bind (start-var end-var) start-end
      `(let ((sm (make-marker))
             (em (make-marker)))
         (unwind-protect
              (progn
                (goto-char (point-min))
                (while (< (point) (point-max))
                  (let ((,vline (point)))
                    (set-marker sm (point))
                    (set-marker em (progn (end-of-line) (point)))
                    (let ((,start-var  (marker-position sm))
                          (,end-var    (marker-position em)))
                      ,@body)
                    (goto-char ,vline)
                    (forward-line 1))))
           (set-marker sm nil)
           (set-marker em nil))
         nil))))





So instead of the replace-regexp, you can use (csvify-r14-buffer).
At the end, you didn't say what resulting file format you wanted. You
could remove the last replace-regexp, and keep the result in csv
format, keep it, and have fields containing commas be left quoted (but
you don't seem to have such data anyways), or write a more sophisticated
command to format csv records into whatever format you want.


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: simple first emacs script
  2010-12-15 18:37     ` Pascal J. Bourguignon
@ 2010-12-16 15:21       ` Tom
  2010-12-16 21:55       ` Stefan Monnier
  1 sibling, 0 replies; 7+ messages in thread
From: Tom @ 2010-12-16 15:21 UTC (permalink / raw)
  To: help-gnu-emacs

Pascal,

Thanks again for this, there is plenty for me to build upon and learn 
from here.  I will go away and ponder it for a while.

Tom



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: simple first emacs script
  2010-12-15 18:37     ` Pascal J. Bourguignon
  2010-12-16 15:21       ` Tom
@ 2010-12-16 21:55       ` Stefan Monnier
  2010-12-17 22:13         ` Thien-Thi Nguyen
  1 sibling, 1 reply; 7+ messages in thread
From: Stefan Monnier @ 2010-12-16 21:55 UTC (permalink / raw)
  To: help-gnu-emacs

> If you want to memorize a buffer position in the course of editing that
> may change its absolute position (insertion and deletions), you may use
> markers (see the functions make-marker and set-marker), but markers need
> to be 'freed' explicitely by reseting them to nil,

Actually, they don't need to be freed explicitly (it may sometimes be
beneficial to performance, but only if there are many of them).

BTW, instead of using markers, you can often avoid the problem
altogether by simply performing the modifications starting from the end
of the region (so while the (point-max) you've computed at the beginning
is not valid at the end any more, it doesn't matter because you're done
processing that part of the buffer).


        Stefan


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: simple first emacs script
  2010-12-16 21:55       ` Stefan Monnier
@ 2010-12-17 22:13         ` Thien-Thi Nguyen
  0 siblings, 0 replies; 7+ messages in thread
From: Thien-Thi Nguyen @ 2010-12-17 22:13 UTC (permalink / raw)
  To: help-gnu-emacs

() Stefan Monnier <monnier@iro.umontreal.ca>
() Thu, 16 Dec 2010 16:55:10 -0500

   modifications starting from the end

An example of this is ‘vc-rcs-annotate-command’ (vc-rcs.el).
Specifically, look for the comment that contains "DTRT".



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2010-12-17 22:13 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-12-15 12:55 simple first emacs script Tom
2010-12-15 14:51 ` Pascal J. Bourguignon
2010-12-15 17:28   ` Tom
2010-12-15 18:37     ` Pascal J. Bourguignon
2010-12-16 15:21       ` Tom
2010-12-16 21:55       ` Stefan Monnier
2010-12-17 22:13         ` Thien-Thi Nguyen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).