the-the 関数 ¶文章を書いていると、この文の冒頭にある「you
you」のように、単語を重ねてしまうことがあります。特に「the」を重ねてしまうことが多いため、重複単語を検出する関数をthe-theと名付けました。
まずは、以下の正規表現を使って重複を検索してみるとよいでしょう。
\\(\\w+[ \t\n]+\\)\\1
この正規表現は、1つ以上の単語構成文字に続き、1つ以上のスペース、タブ、または改行にマッチします。ただし、1つ目の単語の末尾である行末と、2つ目の単語の末尾であるスペースとは異なるため、異なる行にある重複した単語は検出されません。(正規表現の詳細については、正規表現検索のほか、The GNU Emacs Manualの正規表現の構文、およびThe GNU Emacs Lisp Reference Manualの正規表現を参照してください。)
単語を構成する文字の重複だけを検索してみるのもいいかもしれませんが、それではうまくいきません。というのも、パターンが “with the” 内の “th” の2箇所のような重複を検出してしまうからです。
もう一つの候補となる正規表現は、単語構成文字に続いて非単語構成文字が出現するパターンを、繰り返し検索するものです。ここでは、‘\\w+’が1つ以上の単語構成文字に、‘\\W*’が0個以上の非単語構成文字にそれぞれマッチします。
\\(\\(\\w+\\)\\W*\\)\\1
やっぱり、役に立たない。
私が使っているパターンはこちらです。完璧ではありませんが、十分使えます。‘\\b’は、単語の先頭または末尾にある場合に限り、空文字列にマッチします。‘[^@ \n\t]+’は、@記号、スペース、改行、またはタブではない任意の文字が1回以上出現する場合にマッチします。
\\b\\([^@ \n\t]+\\)[ \n\t]+\\1\\b
もっと複雑な式を書くこともできますが、この式で十分だと思ったので、これを使っています。
.emacsファイルに含めているthe-the関数と、便利なグローバルキーバインドがこちらです:
(defun the-the () "Search forward for for a duplicated word." (interactive) (message "Searching for for duplicated words ...") (push-mark)
;; This regexp is not perfect
;; but is fairly good over all:
(if (re-search-forward
"\\b\\([^@ \n\t]+\\)[ \n\t]+\\1\\b" nil 'move)
(message "Found duplicated word.")
(message "End of buffer")))
;; Bind 'the-the' to C-c \ (keymap-global-set "C-c \\" 'the-the)
以下はテストテキストです:
one two two three four five five six seven
関数定義内で上記に示した他の正規表現に置き換えて、このリストのそれぞれを試すことができます。