Skip to content

Commit 520f25f

Browse files
committed
much simpler implementation, using fileter and common prefix for fast checking of common prefixes for each line
1 parent 8dce5ab commit 520f25f

File tree

2 files changed

+13
-37
lines changed

2 files changed

+13
-37
lines changed

Lib/textwrap.py

Lines changed: 12 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -434,43 +434,20 @@ def dedent(text):
434434
if "\n" not in text:
435435
return text # Single line has no dedent
436436

437-
# Split text into lines, preserving line endings
438-
lines = text.splitlines(keepends=True)
439-
440-
# Process in a single pass to find:
441-
# 1. Leading whitespace of non-blank lines
442-
# 2. Whether a line has zero leading whitespace (optimization)
443-
non_blank_whites = []
444-
has_zero_margin = False
445-
446-
for line in lines:
447-
stripped = line.strip()
448-
if stripped: # Non-blank line
449-
leading = line[:len(line) - len(line.lstrip())]
450-
non_blank_whites.append(leading)
451-
# Early detection of zero margin case
452-
if not leading:
453-
has_zero_margin = True
454-
break # No need to check more lines
455-
456-
# If all lines are blank, normalize them
457-
if not non_blank_whites:
458-
# Preallocate result list
459-
return "".join(["\n" if line.endswith("\n") else "" for line in lines])
460-
461-
# Skip commonprefix calculation if we already know there's no margin
462-
if has_zero_margin:
463-
margin_len = 0
464-
else:
465-
common = os.path.commonprefix(non_blank_whites)
466-
margin_len = len(common)
467-
468-
# No common margin case - just normalize blank lines
469-
if margin_len == 0:
470-
return "".join([line if line.strip() else "\n" if line.endswith("\n") else "" for line in lines])
437+
lines = text.split("\n")
438+
439+
splitting = os.path.commonprefix(tuple(filter(lambda x: x.lstrip(), lines)))
440+
441+
margin_len = 0
442+
443+
for split in splitting:
444+
if ' \t' in split :
445+
margin_len += 1
446+
else:
447+
break
471448

472449
# Apply margin removal (most common case) with minimal operations
473-
return "".join([line[margin_len:] if line.strip() else "\n" if line.endswith("\n") else "" for line in lines])
450+
return "\n".join([line[margin_len:] if line.strip() else "\n" if line.endswith("\n") else "" for line in lines])
474451

475452

476453
def indent(text, prefix, predicate=None):
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
Optimized :func: ``textwrap.dedent``. It is now 4x faster than before for large inputs. Function now has the command argument to remove all common prefixes as well with ``only_whitespace`` instead of just whitespaces.
2-
Patch by Marius Juston.
1+
Optimized :func:`textwrap.dedent`. It is now 2x faster than before for large inputs.

0 commit comments

Comments
 (0)