Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Trailing whitespace strip in <pre> is quadratic on a long whitespace run

オープン 初心者向け
#286 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

@ac1982 がすでに取り組んでいます。

2026年10月11日 から。

  • #287 @ac1982 による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
78/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
python
領域
tooling

調査の方向性

処理が遅いのは markdownify/init.py の 78 行目付近にある strip_pre 内の re_pre_rstrip.sub で、issue では str.rstrip の呼び出しに置き換えることが提案されています。re_pre_lstrip と re_pre_rstrip の定義を読んでから、末尾の空白を含む 64 KB の <pre> ブロックを markdownify() に渡して再現してください。このケースが 1 秒よりずっと短い時間で完了し、既存の 83 件のテストスイートが引き続き通り、issue に挙げられた <pre> の表記を新しいタイミングテストで網羅できれば完了です。

索引モデルが issue の本文から書いたものです。

説明

strip_pre() takes quadratic time on a <pre> block whose trailing whitespace run is a run of spaces not ended by a newline. Measured through markdownify() on tag 1.2.3, both trees in one isolated run:

HTML before after
16,000 B 0.6881 s 0.0003 s
32,000 B 2.6570 s 0.0004 s
65,536 B 9.1117 s 0.0007 s
131,072 B 35.5100 s 0.0014 s
16,000 B of ordinary words 0.0011 s 0.0009 s

Each doubling of the block quadruples the time, so the cost belongs to the shape rather than the size - the last row is a document of the same size that converts in a millisecond. The input is an HTML document, so nothing bounds it, and this is the default path: strip_pre defaults to STRIP, while STRIP_ONE uses the separate re_pre_rstrip1 = r'\n *$' and is unaffected.

Cause. re_pre_rstrip = re.compile(r'[ \n]*$') applied with .sub() at __init__.py:78. .sub restarts at every position in the string, and at each one the unbounded [ \n]* run expands and then backtracks looking for the $ that the following character denies.

It is worth saying why the costly shape is spaces and not newlines, because it is not obvious from the pattern alone: re_pre_lstrip = r'^[ \n]*\n' runs on the line before, so a leading newline run is consumed there and re_pre_rstrip is handed a one-character string. With no newline in the block, lstrip does not fire and rstrip receives the whole thing. On the same 65,536-byte input a newline run costs 0.0001 s and a space run 9.3704 s.

Fix. The docstring already describes a strip, so use one:

-    text = re_pre_rstrip.sub('', text)
+    text = text.rstrip(' \n')

Verification.

  • Test suite on both trees at tag 1.2.3: 83 passed, unchanged, with each run asserting which markdownify/__init__.py was loaded and whether it still contains the regex call.
  • Differential: 0 differences from current behaviour across all 29,524 strings of length 0 to 9 over {space, newline, x} - the whole alphabet the two patterns act on.
  • A new test converts a 64 KB <pre> block in under 0.5 s and checks seven <pre> spellings (blank lines, leading and trailing spaces, indentation, empty, whitespace-only). On 1.2.3 the timing test fails and the behaviour test passes.
  • Shapes aimed at the fix rather than the original (pure space run with no terminator, a leading x then a run, many short runs split by x) are all flat: worst 0.0003 s at 65,536 B.

re_pre_rstrip is now unused. I have deliberately left the definition in place to keep the diff to one line, since it is a module-level name that something downstream may import; say the word and I will remove it.

I am happy to open a pull request with the patch if that is easier.

Found with AI assistance (Claude) and verified by hand.

Patch: full patch
--- a/markdownify/__init__.py
+++ b/markdownify/__init__.py
@@ -75,7 +75,7 @@
 def strip_pre(text):
     """Strip all leading and trailing newlines from a <pre> string."""
     text = re_pre_lstrip.sub('', text)
-    text = re_pre_rstrip.sub('', text)
+    text = text.rstrip(' \n')
     return text
主要言語
Python
スター
2.3k
フォーク
210
PR マージ指標
30日以内にマージされた PR はありません

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

matthewwithanm/python-markdownify のほかの issue

matthewwithanm/python-markdownify の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。