有没有办法让`fill-paragraph`在句子结尾处停止?

时间:2011-09-26 11:23:13

标签: emacs

有时候需要在单独的一行中开始段落中的每个句子。例如,这使得更容易区分大型文本文档,因为一个句子的更改不会影响整个段落。一些标记系统(例如* roff)也要求每个句子在新行上开始。

有没有办法,例如通过明智地重新定义paragraph-separateparagraph-start,使fill-paragraph在句子之间停止?

(注意:我使用的是Emacs 23.3.1)


更新:示例mdoc(* roff)标记:

The
.Nm
utility makes a series of passes with increasing block sizes.
In each pass, it either reads or writes (or both) a number of
non-consecutive blocks at increasing offsets relative to the ideal
alignment, which is assumed to be multiples of the block size.
The results are presented in terms of time elapsed, transactions per
second and kB per second.

这是一个包含三个句子的单个段落,每个句子都在一个单独的行上开始,即使前一行的第一个单词有空间。目前,fill-paragraph会将此转换为

The
.Nm
utility makes a series of passes with increasing block sizes.  In each
pass, it either reads or writes (or both) a number of non-consecutive
blocks at increasing offsets relative to the ideal alignment, which is
assumed to be multiples of the block size.  The results are presented
in terms of time elapsed, transactions per second and kB per second.

这是我想要避免的。


更新:重复句子和段落

我看到我的问题有点不清楚,因为我使用术语“段落”来指代Emacs所谓的段落以及最终作为我使用的任何处理器的输出中的连续文本块( groff,乳胶等)。澄清一下,

  • 我需要把句子放在一起,两者之间没有任何空白; groff不喜欢空行,而latex将它们视为段落分隔符。
  • 我需要fill-paragraph对单个句子进行操作,即我想将一个段落重新定义为在空白行或前一段结尾之后开始的段落,并以句点后跟换行符结束字符或至少两个空白字符。
  • 我希望fill-paragraph将一段文字分成单个句子,但我认为不能轻易完成。

例如,如果我键入以下内容:

The
.Nm
utility makes a series of passes with increasing block sizes.
In each pass, it either reads or writes (or both) a number of non-consecutive blocks at increasing offsets relative to the ideal alignment, which is assumed to be multiples of the block size.
The results are presented in terms of time elapsed, transactions per second and kB per second.

然后将该点移动到以“每次传递”开头的行并按M-q,我应该得到以下内容:

The
.Nm
utility makes a series of passes with increasing block sizes.
In each pass, it either reads or writes (or both) a number of
non-consecutive blocks at increasing offsets relative to the ideal
alignment, which is assumed to be multiples of the block size.
The results are presented in terms of time elapsed, transactions per second and kB per second.

请注意,最后一句不受影响。

3 个答案:

答案 0 :(得分:1)

如何告诉paragraph-start查找以大写字母开头的任何行:

"\f\\|[     ]*$\\|^[A-Z]"

请注意,新部分为\\^[A-Z]

这应该适用于大多数情况,你只需要注意你有一个大写中期句子的罕见情况,而这个句子恰好足够长,可以在句子中间的单词之前打破。

编辑:你可能也想考虑缩进:

"\f\\|[     ]*$\\|^[    ]*[A-Z]"

方括号之间的空格包含空格和制表符。

编辑:你需要关闭case-fold-search才能使用,否则在比赛中不会区分大写字母和小写字母!

编辑:如果你想关闭这个函数的case-fold-search,请将以下内容绑定到M-q(您可以在本地或全局进行,如您所见)。

(defun my-fill-paragraph ()
  (interactive)
  (let ((case-fold-search nil))
    (fill-paragraph)))

答案 1 :(得分:1)

这是DTRT吗?

(defun separate-sentences (&optional beg end)
  "ensure each sentence ends with a new line.
When no region specified, use current paragraph."
  (interactive (when (use-region-p)
                   (list (region-beginning) (region-end))))
  (unless (and beg end)
    (save-excursion
      (forward-paragraph -1)
      (setq beg (point))
      (forward-paragraph 1)
      (setq end (point))))
  (setq end (if (markerp end)
                end
              (set-marker (make-marker) end)))
  (save-excursion
    (goto-char beg)
    (while (re-search-forward (sentence-end) end t)
      (unless (or (looking-at-p "[ \t]*$")
                  (looking-back "^[ \t]*"))
        (insert "\n")))))

(defun fill-paragraph-sentence-groups (justify)
  "Groups of sentences filled together.  A sentence ending with newline marks end of group."
  (save-excursion
    (save-restriction
      (narrow-to-region (progn (forward-paragraph -1) (point))
                        (progn (forward-paragraph 1) (point)))
      (goto-char (point-min))
      (skip-chars-forward " \t\n")
      (while (not (or (looking-at-p paragraph-separate)
                      (eobp)))
        (fill-region (point)
                     (progn
                       (loop do (forward-sentence 1)
                             until (looking-at "[ \t]*$"))
                       (point))
                     justify)
        (unless (looking-back "^[ \t]*")
          (forward-line 1)))
      t)))

(defun fill-paragraph-sentence-individual (justify)
  "Each sentence in paragraph is put on new line."
  (save-excursion
    (separate-sentences)
    (fill-paragraph-sentence-groups justify)))

;; deployment option 1: add to major-mode hook

(add-hook 'text-mode-hook (lambda ()
                            (set (make-local-variable fill-paragraph-function) 'fill-paragraph-sentence-individual)))

;; deployment option 2: call my-fill-paragraph any where

(defun my-fill-paragraph (arg)
  (interactive "*P")
  (let ((fill-paragraph-function 'fill-paragraph-sentence-individual))
    (fill-paragraph arg)))

上面介绍了两段填充功能。一个分组句子不会在新行上结束。另一个将每个句子分成一个新行。

我只展示如何部署个人,因为这是OP想要的。如果您愿意,请按照模型部署组版本。

答案 2 :(得分:0)

您可以使用fill-region,毫不奇怪,只会填充当前区域。基于此,您可以定义fill-sentence函数。我想用一种简单的方法来检测这样的句子就是说:

  • 如果该行以.?!结尾,则为句末行。

  • 如果一条句子的前导行为空或句末行,则该行开始一句话。

尽管如此,让它在所有情况下都能正常工作是相当棘手的。