Skip to main content
Bounty Ended with 50 reputation awarded by George
the first version was just a regular program that dealt with a whole buffer. This one uses mark restrictions to operate on a subset of the buffer. Also, better output.
Source Link

I spent way too much time noodling around with thisHere is a slightly revised version tested on GNU Emacs:

(defun bracket-sum-line-split-col3 (col3 unit-char)
  (let ((regex-pat1 (format "\\([-0-9.]+[ ]*\\)%s" unit-char))
        (regex-pat2 (format "\\([-0-9.]+[ ]*\\)%s[ ]*,[ ]*\\([-0-9.]+[ ]*\\)%s" unit-char unit-char)))
    (if (string-match regex-pat2 col3)
        (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 2 col3)))
      (if (string-match regex-pat1 col3)
          (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 1 col3)))
        )
      )
    )
  )

(defun bracket-sum-line (line unit-char)
  (if (string-match "|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|" line)
      (let ((col1 (match-string 1 line))
            (col2 (match-string 2 line))
            (col3 (match-string 3 line)))
        (let* ((ret (bracket-sum-line-split-col3 col3 unit-char))
               (val1 (car ret))
               (val2 (cadr ret)))
          (list col1 col2 val1 val2))
        )))

(defun bracket-sum-output (results unit-char)
  (let (retval)
    (maphash (lambda (key value)
               (push (format "|%s|%f %s|%f %s|" key (nth 0 value) unit-char (nth 1 value) unit-char) retval)
               (message "hash key: \"%s\"" key)
               )
             results)
    (push "|Category|col1|col2|" retval) ;; header
    (push "\nCOMPLETED SUMS" retval)
    (insert (mapconcat 'identity retval "\n")) ;;retval
    ) ;; end let
)

(defun bracket-sum (begin end char)
  (interactive "r\nM String: ")
  (save-restriction
    (save-excursion
      (narrow-to-region begin end)
      (goto-char (point-min))
      (let ((result (make-hash-table :test 'equal))
            (curr-line 1)
            (begin (point))
            (end (point-max)))
        (while (< (point) end)
          ;; (buffer-substring
          (forward-line 1)

          ;; work done here
          (message "where %d %d %d \"%s\"" begin (point) curr-line (buffer-substring begin (- (point) 1)))
          (if (> curr-line 1) ; skip table header
              (let* ((ret (bracket-sum-line (buffer-substring begin (- (point) 1))  char))
                     (col1 (nth 0 ret))
                     (col2 (nth 1 ret))
                     (val1 (nth 2 ret))
                     (val2 (nth 3 ret)))
                (if (string= col2 "COMPLETE")
                    (if (gethash col1 result)
                        (let* ((res (gethash col1 result))
                               (res1 (nth 0 res))
                               (res2 (nth 1 res)))
                          (puthash col1 (list (+ val1 res1) (+ val2 res2)) result)) ;; existing entry
                      (puthash col1 (list val1 val2) result)) ;; new entry
                  (unless (gethash col1 result)
                    (puthash col1 (list 0 0) result))) ;; not complete
                )
            ) ;; end if not table header if

          ;; goto next line
          (setq curr-line (+ 1 curr-line))
          (setq begin (point))) ;; end while

        (message "%s" result)
        (bracket-sum-output result char) ;; print output
        ))))

ok so what is happening here. I used this test file To Run:

  1. mark (aka select) the area in the org buffer leaving the cursor on the line below the last one in the table

inputstep 1

and I get this output:

  1. call the function

outputstep 2

when I evaluate:

  1. provide the column arg
(format "%s" (bracket-sum "conditional_sum.org" "μ"))

step 3

There is probably a much easier way. My LISP is rusty. HereHere is the codewhat I get:

(defun bracket-sum-line-split-col3 (col3 unit-char)
  (let ((regex-pat1 (format "\\([-0-9.]+[ ]*\\)%s" unit-char))
        (regex-pat2 (format "\\([-0-9.]+[ ]*\\)%s[ ]*,[ ]*\\([-0-9.]+[ ]*\\)%s" unit-char unit-char)))
    (if (string-match regex-pat2 col3)
        ;; (message "match two %f %f" (string-to-number (match-string 1 col3)) (string-to-number (match-string 2 col3)))
        (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 2 col3)))
      (if (string-match regex-pat1 col3)
          ;; (message "match one %f %f" (string-to-number (match-string 1 col3)) (string-to-number (match-string 1 col3)))
          (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 1 col3)))
        )
      )
    )
  )

(defun bracket-sum-line (line unit-char)
  (if (string-match "|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|" line)
      (let ((col1 (match-string 1 line))
            (col2 (match-string 2 line))
            (col3 (match-string 3 line)))
        ;;(message "line split: \"%s\" \"%s\" \"%s\"" col1 col2 col3)
        (let* ((ret (bracket-sum-line-split-col3 col3 unit-char))
               (val1 (car ret))
               (val2 (cadr ret)))
          ;; (message "vals %f %f" val1 val2))
          (list col1 col2 val1 val2))
  )))

(defun bracket-sum (buffer unit-char)
  (save-excursion
    (or (bufferp buffer)
        (setq buffer (get-buffer buffer)))
    (set-buffer buffer)
    (let ((bstart (point-min))
          (bend (point-max))
          (result (make-hash-table :test 'equal))
          (line 0))
      ;; (message "buffer start end %d %d" bstart bend)
      (goto-char bstart)
      (while (< (point) bend)
        ; (message "line %d %d" line (point))

        (if (re-search-forward "^\\(.*+\\)$") ; try to grap the whole line
            (if (> line 0) ; skip table header
                (let* ((ret (bracket-sum-line (match-string 1) unit-char))
                       (col1 (nth 0 ret))
                       (col2 (nth 1 ret))
                       (val1 (nth 2 ret))
                       (val2 (nth 3 ret)))
                  (if (string= col2 "COMPLETE")
                      ;; (message "CLOSE %s %s %f %f" col1 col2 val1 val2))
                      (if (gethash col1 result)
                          (let* ((res (gethash col1 result))
                                 (res1 (nth 0 res))
                                 (res2 (nth 1 res)))
                            (puthash col1 (list (+ val1 res1) (+ val2 res2)) result)) ;; existing entry
                        (puthash col1 (list val1 val2) result)) ;; new entry
                    (unless (gethash col1 result)
                      (puthash col1 (list 0 0) result))) ;; not complete
                  )
              )
          )
        ;; let do the next line
        (forward-line 1)
        (setq line (1+ line))
        ) ;; end while

      ;; lets try to format the return list
      (let (retval)
        (maphash (lambda (key value)
                   (push (format "Category: %s, %f %s, %f %s.\n" key (nth 0 value) unit-char (nth 1 value) unit-char) retval))
                 result)
        retval)
      )))
      
;; (format "%s" (bracket-sum "conditional_sum.org" "μ"))

results

Please note some minor tweaks will be required to use the interactive restriction based selection. To use in org mode I would just CTRL-U then CTRL-X + CTRL-E to have emacs dump the text tojust go into the results and hit tab and org buffermode will format it. I only tested it in GNU Emacs.

I spent way too much time noodling around with this. I used this test file:

input

and I get this output:

output

when I evaluate:

(format "%s" (bracket-sum "conditional_sum.org" "μ"))

There is probably a much easier way. My LISP is rusty. Here is the code:

(defun bracket-sum-line-split-col3 (col3 unit-char)
  (let ((regex-pat1 (format "\\([-0-9.]+[ ]*\\)%s" unit-char))
        (regex-pat2 (format "\\([-0-9.]+[ ]*\\)%s[ ]*,[ ]*\\([-0-9.]+[ ]*\\)%s" unit-char unit-char)))
    (if (string-match regex-pat2 col3)
        ;; (message "match two %f %f" (string-to-number (match-string 1 col3)) (string-to-number (match-string 2 col3)))
        (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 2 col3)))
      (if (string-match regex-pat1 col3)
          ;; (message "match one %f %f" (string-to-number (match-string 1 col3)) (string-to-number (match-string 1 col3)))
          (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 1 col3)))
        )
      )
    )
  )

(defun bracket-sum-line (line unit-char)
  (if (string-match "|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|" line)
      (let ((col1 (match-string 1 line))
            (col2 (match-string 2 line))
            (col3 (match-string 3 line)))
        ;;(message "line split: \"%s\" \"%s\" \"%s\"" col1 col2 col3)
        (let* ((ret (bracket-sum-line-split-col3 col3 unit-char))
               (val1 (car ret))
               (val2 (cadr ret)))
          ;; (message "vals %f %f" val1 val2))
          (list col1 col2 val1 val2))
  )))

(defun bracket-sum (buffer unit-char)
  (save-excursion
    (or (bufferp buffer)
        (setq buffer (get-buffer buffer)))
    (set-buffer buffer)
    (let ((bstart (point-min))
          (bend (point-max))
          (result (make-hash-table :test 'equal))
          (line 0))
      ;; (message "buffer start end %d %d" bstart bend)
      (goto-char bstart)
      (while (< (point) bend)
        ; (message "line %d %d" line (point))

        (if (re-search-forward "^\\(.*+\\)$") ; try to grap the whole line
            (if (> line 0) ; skip table header
                (let* ((ret (bracket-sum-line (match-string 1) unit-char))
                       (col1 (nth 0 ret))
                       (col2 (nth 1 ret))
                       (val1 (nth 2 ret))
                       (val2 (nth 3 ret)))
                  (if (string= col2 "COMPLETE")
                      ;; (message "CLOSE %s %s %f %f" col1 col2 val1 val2))
                      (if (gethash col1 result)
                          (let* ((res (gethash col1 result))
                                 (res1 (nth 0 res))
                                 (res2 (nth 1 res)))
                            (puthash col1 (list (+ val1 res1) (+ val2 res2)) result)) ;; existing entry
                        (puthash col1 (list val1 val2) result)) ;; new entry
                    (unless (gethash col1 result)
                      (puthash col1 (list 0 0) result))) ;; not complete
                  )
              )
          )
        ;; let do the next line
        (forward-line 1)
        (setq line (1+ line))
        ) ;; end while

      ;; lets try to format the return list
      (let (retval)
        (maphash (lambda (key value)
                   (push (format "Category: %s, %f %s, %f %s.\n" key (nth 0 value) unit-char (nth 1 value) unit-char) retval))
                 result)
        retval)
      )))
      
;; (format "%s" (bracket-sum "conditional_sum.org" "μ"))

Please note some minor tweaks will be required to use the interactive restriction based selection. To use in org mode I would just CTRL-U then CTRL-X + CTRL-E to have emacs dump the text to the org buffer.

Here is a slightly revised version tested on GNU Emacs:

(defun bracket-sum-line-split-col3 (col3 unit-char)
  (let ((regex-pat1 (format "\\([-0-9.]+[ ]*\\)%s" unit-char))
        (regex-pat2 (format "\\([-0-9.]+[ ]*\\)%s[ ]*,[ ]*\\([-0-9.]+[ ]*\\)%s" unit-char unit-char)))
    (if (string-match regex-pat2 col3)
        (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 2 col3)))
      (if (string-match regex-pat1 col3)
          (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 1 col3)))
        )
      )
    )
  )

(defun bracket-sum-line (line unit-char)
  (if (string-match "|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|" line)
      (let ((col1 (match-string 1 line))
            (col2 (match-string 2 line))
            (col3 (match-string 3 line)))
        (let* ((ret (bracket-sum-line-split-col3 col3 unit-char))
               (val1 (car ret))
               (val2 (cadr ret)))
          (list col1 col2 val1 val2))
        )))

(defun bracket-sum-output (results unit-char)
  (let (retval)
    (maphash (lambda (key value)
               (push (format "|%s|%f %s|%f %s|" key (nth 0 value) unit-char (nth 1 value) unit-char) retval)
               (message "hash key: \"%s\"" key)
               )
             results)
    (push "|Category|col1|col2|" retval) ;; header
    (push "\nCOMPLETED SUMS" retval)
    (insert (mapconcat 'identity retval "\n")) ;;retval
    ) ;; end let
)

(defun bracket-sum (begin end char)
  (interactive "r\nM String: ")
  (save-restriction
    (save-excursion
      (narrow-to-region begin end)
      (goto-char (point-min))
      (let ((result (make-hash-table :test 'equal))
            (curr-line 1)
            (begin (point))
            (end (point-max)))
        (while (< (point) end)
          ;; (buffer-substring
          (forward-line 1)

          ;; work done here
          (message "where %d %d %d \"%s\"" begin (point) curr-line (buffer-substring begin (- (point) 1)))
          (if (> curr-line 1) ; skip table header
              (let* ((ret (bracket-sum-line (buffer-substring begin (- (point) 1))  char))
                     (col1 (nth 0 ret))
                     (col2 (nth 1 ret))
                     (val1 (nth 2 ret))
                     (val2 (nth 3 ret)))
                (if (string= col2 "COMPLETE")
                    (if (gethash col1 result)
                        (let* ((res (gethash col1 result))
                               (res1 (nth 0 res))
                               (res2 (nth 1 res)))
                          (puthash col1 (list (+ val1 res1) (+ val2 res2)) result)) ;; existing entry
                      (puthash col1 (list val1 val2) result)) ;; new entry
                  (unless (gethash col1 result)
                    (puthash col1 (list 0 0) result))) ;; not complete
                )
            ) ;; end if not table header if

          ;; goto next line
          (setq curr-line (+ 1 curr-line))
          (setq begin (point))) ;; end while

        (message "%s" result)
        (bracket-sum-output result char) ;; print output
        ))))

ok so what is happening here. To Run:

  1. mark (aka select) the area in the org buffer leaving the cursor on the line below the last one in the table

step 1

  1. call the function

step 2

  1. provide the column arg

step 3

Here is what I get:

results

then just go into the results and hit tab and org mode will format it. I only tested it in GNU Emacs.

Source Link

I spent way too much time noodling around with this. I used this test file:

input

and I get this output:

output

when I evaluate:

(format "%s" (bracket-sum "conditional_sum.org" "μ"))

There is probably a much easier way. My LISP is rusty. Here is the code:

(defun bracket-sum-line-split-col3 (col3 unit-char)
  (let ((regex-pat1 (format "\\([-0-9.]+[ ]*\\)%s" unit-char))
        (regex-pat2 (format "\\([-0-9.]+[ ]*\\)%s[ ]*,[ ]*\\([-0-9.]+[ ]*\\)%s" unit-char unit-char)))
    (if (string-match regex-pat2 col3)
        ;; (message "match two %f %f" (string-to-number (match-string 1 col3)) (string-to-number (match-string 2 col3)))
        (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 2 col3)))
      (if (string-match regex-pat1 col3)
          ;; (message "match one %f %f" (string-to-number (match-string 1 col3)) (string-to-number (match-string 1 col3)))
          (list (string-to-number (match-string 1 col3)) (string-to-number (match-string 1 col3)))
        )
      )
    )
  )

(defun bracket-sum-line (line unit-char)
  (if (string-match "|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|[ ]*\\(.+?\\)[ ]*|" line)
      (let ((col1 (match-string 1 line))
            (col2 (match-string 2 line))
            (col3 (match-string 3 line)))
        ;;(message "line split: \"%s\" \"%s\" \"%s\"" col1 col2 col3)
        (let* ((ret (bracket-sum-line-split-col3 col3 unit-char))
               (val1 (car ret))
               (val2 (cadr ret)))
          ;; (message "vals %f %f" val1 val2))
          (list col1 col2 val1 val2))
  )))

(defun bracket-sum (buffer unit-char)
  (save-excursion
    (or (bufferp buffer)
        (setq buffer (get-buffer buffer)))
    (set-buffer buffer)
    (let ((bstart (point-min))
          (bend (point-max))
          (result (make-hash-table :test 'equal))
          (line 0))
      ;; (message "buffer start end %d %d" bstart bend)
      (goto-char bstart)
      (while (< (point) bend)
        ; (message "line %d %d" line (point))

        (if (re-search-forward "^\\(.*+\\)$") ; try to grap the whole line
            (if (> line 0) ; skip table header
                (let* ((ret (bracket-sum-line (match-string 1) unit-char))
                       (col1 (nth 0 ret))
                       (col2 (nth 1 ret))
                       (val1 (nth 2 ret))
                       (val2 (nth 3 ret)))
                  (if (string= col2 "COMPLETE")
                      ;; (message "CLOSE %s %s %f %f" col1 col2 val1 val2))
                      (if (gethash col1 result)
                          (let* ((res (gethash col1 result))
                                 (res1 (nth 0 res))
                                 (res2 (nth 1 res)))
                            (puthash col1 (list (+ val1 res1) (+ val2 res2)) result)) ;; existing entry
                        (puthash col1 (list val1 val2) result)) ;; new entry
                    (unless (gethash col1 result)
                      (puthash col1 (list 0 0) result))) ;; not complete
                  )
              )
          )
        ;; let do the next line
        (forward-line 1)
        (setq line (1+ line))
        ) ;; end while

      ;; lets try to format the return list
      (let (retval)
        (maphash (lambda (key value)
                   (push (format "Category: %s, %f %s, %f %s.\n" key (nth 0 value) unit-char (nth 1 value) unit-char) retval))
                 result)
        retval)
      )))
      
;; (format "%s" (bracket-sum "conditional_sum.org" "μ"))

Please note some minor tweaks will be required to use the interactive restriction based selection. To use in org mode I would just CTRL-U then CTRL-X + CTRL-E to have emacs dump the text to the org buffer.

James