0

This function is supposed to replace matches with a shortened version using multiple rules rather than just a single one. For the word counter, coun gets replaced by k, resulting in the shortened word kter.

But I am struggling for the case where the replacement has to be done at the end. So that family gets replaced by faml (replacing ily match with l).

(defun shorten-word-b ()
  "Shortens a word according to specific rules."

  (interactive)

  (let* ((bounds (bounds-of-thing-at-point 'word))
     (s (car bounds))
     (case-fold-search nil)
     (p (point-marker)))

    (when s
      (goto-char s)
      (cond
       ;;-----------------------------------------------
       ((looking-at (regexp-opt
           '("cog" "col" "com" "con" "cor" "cum" "coun") "\\<\\("))
        (replace-match "k"))
       ;;-----------------------------------------------       
       ((looking-at (regexp-opt
           '("ley" "ily" "ly") "\\)\\>"))
        (replace-match "l"))
       ;;-----------------------------------------------
       (t nil))
      (goto-char p))
    (set-marker p nil)))

Here are some examples

Before: Counter
After: kter

Before: family
After: faml 

Where point can be placed anywhere, with next character being a character of word.

2
  • 1
    Please add "Before:" and "After:" samples including the location of point. Commented Aug 16, 2022 at 14:04
  • @PhilHudson: bounds-of-things-at-point returns a dotted pair whose car is the beginning of the thing-at-point and whose cdr is the end of it (in this case the thing is a word). So (goto-char s) puts point at the beginning of the word in preparation for the cond.
    – NickD
    Commented Aug 17, 2022 at 4:23

2 Answers 2

1

I don't know if this helps, but here is a variation of what you wrote above that works in all the cases I've tried:

(defun shorten-word-b ()
  "Shortens the word at point according to specific rules."

  (interactive)

  (let* ((bounds (bounds-of-thing-at-point 'word))
         (s (car bounds))
         (case-fold-search nil)
         (p (point-marker)))
    
    (when s
      (goto-char s)
      (cond
       ;;-----------------------------------------------
       ;; deal with prefixes
       ((looking-at (concat "\\<"
                            (regexp-opt
                             '("cog" "col" "com" "con" "cor" "cum" "coun"))))
        (replace-match "k"))
       ;;-----------------------------------------------       
       ;; deal with suffixes - be careful not to overstep the bounds
       ((search-forward-regexp (concat (regexp-opt '("ley" "ily" "ly")) "\\>") (cdr bounds) t)
        (replace-match "l"))
       ;;-----------------------------------------------
       (t nil))
      (goto-char p))
    (set-marker p nil)))

The tests I tried:

cognition
confidence
counter
columnar
cumulative
contiguous
correlative
abscond
score
scum
scoliosis
discount
discography
family
oleley
only
lye
familiar
unrelated
not-a-match

Unfortunately, neither regexp catches the case of a prefix or a suffix being the whole "word": con becomes k and ily becomes l. You have to complicate the regexps to catch those cases and not do the contraction.

3
  • There is no need for complication, making replacement still acceptable.
    – Dilna
    Commented Aug 17, 2022 at 3:35
  • 1
    Fixed a bug: check the edit history to see what I changed.
    – NickD
    Commented Aug 17, 2022 at 5:07
  • You are quite right.
    – Dilna
    Commented Aug 17, 2022 at 5:18
0

The problem is the second argument to the second regexp-opt form. That argument gets prefixed; your call implies that you want it to be suffixed, but regexp-opt does not offer you that facility.

What you need is something like this (untested):

((looking-at
   (concat
    (regexp-opt '("ley" "ily" "ly")) "\\b"))  
  (replace-match "l"))

where "\\b" is the word-boundary matcher.

9
  • It's worse than that: if point is at the f of family, then using looking-at to seach for the ily at the end is just not going to match. It has to be at the i of ily. I think looking-at is the wrong interface here.
    – NickD
    Commented Aug 16, 2022 at 14:02
  • Good point. I'll add a comment asking for details. Commented Aug 16, 2022 at 14:04
  • What would be your recommendation that replaces looking-at? Would the change apply to all cases?
    – Dilna
    Commented Aug 16, 2022 at 19:20
  • Should I continue with (insert (replace-regexp-in-string as I had done before?
    – Dilna
    Commented Aug 16, 2022 at 19:22
  • @PhilHudson I progressed with ((looking-at (concat "[[:alpha:]]+[-]?" "\\(" (regexp-opt '("ley" "ily" "ly")) "\\)\\>")). Why does it turn family to famil, rather than faml?
    – Dilna
    Commented Aug 17, 2022 at 0:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.