Emacs: Convert Chinese/Japanese Full-Width/Half-Width Punctuations 🚀

By Xah Lee. Date: . Last updated: .

Here's a command to convert between Full-Width/Half-Width punctuation characters used in Chinese and Japanese text. (全角 半角 转换) [see Unicode: Full-Width Characters]

put this in your Emacs Init File:

(defun xah-convert-english-chinese-punctuation (&optional Begin End ToDirection)
  "Convert punctuation from/to English/Chinese characters.

When called interactively, do current line or selection. The conversion direction is automatically determined.

If `universal-argument' is called, ask user for change direction.

When called in lisp code, Begin End are region begin/end positions. ToDirection must be any of the following string values:

chinese
english
auto

URL `http://xahlee.info/emacs/emacs/elisp_convert_chinese_punctuation.html'
Version: 2012-12-10 2022-05-18 2023-08-26 2023-11-25"
  (interactive)
  (let (xp1 xp2 xinputStr xcontainChinese
            (xengToChinesePairs
             [
              [". " "。"]
              [".\n" "。\n"]
              [", " ","]
              [",\n" ",\n"]
              [": " ":"]
              ["; " ";"]
              ["? " "?"] ; no space after
              ["! " "!"]
              ["& " "&"]
              [" (" "("]
              [") " ")"]
              ;; for inside HTML
              [".</" "。</"]
              ["?</" "?</"]
              [":</" ":</"]
              [" " " "]
              ]
             ))
    (if (and Begin End)
        (setq xp1 Begin xp2 End)
      (if (region-active-p)
          (setq xp1 (region-beginning) xp2 (region-end))
        (setq xp1 (line-beginning-position) xp2 (line-end-position))))
    (setq xinputStr (buffer-substring-no-properties xp1 xp2))

    (when (not ToDirection)
      (setq ToDirection (if current-prefix-arg
                            (completing-read
                             "Change to: "
                             '("english"  "chinese")
                             nil
                             t)
                          "auto"
                          )))

    (setq xcontainChinese
          (seq-some
           (lambda (x) (string-match (aref x 1) xinputStr))
           xengToChinesePairs))

    (when (string-equal ToDirection "auto")
      (setq
       ToDirection
       (if xcontainChinese
           "english"
         "chinese")))
    (save-restriction
      (narrow-to-region xp1 xp2)
      (mapc
       (lambda (xx)
         (progn
           (goto-char (point-min))
           (while (search-forward (aref xx 0) nil t)
             (replace-match (aref xx 1)))))
       (cond
        ((string-equal ToDirection "chinese") xengToChinesePairs)
        ((string-equal ToDirection "english") (mapcar (lambda (x) (vector (elt x 1) (elt x 0))) xengToChinesePairs))
        (t (user-error "Your 3rd argument 「%s」 isn't valid" ToDirection))))
      (goto-char (point-max)))))

Emacs Chinese Topics