Skip to main content

textswap

Bulk text replacement in files using dictionary mappings.

PyPI version License: GPL v3

Replace text across multiple files using find/replace dictionaries. Supports bidirectional replacement (keys-to-values or values-to-keys).

Installation

pip install textswap

Quick Start

  1. Create a config file (config.json):
{
  "dictionaries": {
    "example": {
      "old_text": "new_text",
      "foo": "bar"
    }
  },
  "ignore_extensions": [".exe", ".bin"],
  "ignore_directories": ["node_modules", ".git"],
  "ignore_file_prefixes": [".", "_"]
}
  1. Run:
textswap -f ./my_folder -d 1

Usage

# Interactive mode
textswap

# With options
textswap --folder ./src --direction 1 --config my_config.json

# Dry run (preview changes with diff output)
textswap -f ./src -d 1 --dry-run

# Back up originals before modifying
textswap -f ./src -d 1 -b ./backups

# Only match whole words (won't touch "category" when renaming "cat")
textswap -f ./src -d 1 -w

# Reverse direction (values-to-keys)
textswap -f ./src -d 2

Options

Option Short Description
--folder -f Folder to process
--direction -d 1 = keys-to-values, 2 = values-to-keys
--config -c Path to config file (default: config.json)
--dict-name -n Dictionary name (auto-selects if only one)
--backup-dir -b Copy originals here (mirroring folder structure) before modifying
--whole-words -w Only match keys as whole words (not inside identifiers)
--dry-run Preview changes without modifying files

Config Format

{
  "dictionaries": {
    "my_replacements": {
      "find_this": "replace_with_this",
      "old": "new"
    }
  },
  "ignore_extensions": [".exe", ".dll"],
  "ignore_directories": ["node_modules", "venv"],
  "ignore_file_prefixes": [".", "_"]
}

How It Works

  1. Load config: Reads your JSON config file containing replacement dictionaries
  2. Walk directory: Recursively traverses the target folder
  3. Filter files: Skips files matching ignore rules (extensions, prefixes, directories)
  4. Read & replace: For each file, reads content and applies all replacements from the dictionary
  5. Write back: Saves modified files (or shows diff in dry-run mode)

All files are processed as UTF-8. Non-UTF-8 files are automatically skipped with a warning.

Dry Run Output

The --dry-run flag shows exactly what would change without modifying files:

$ textswap -f ./src -d 1 --dry-run
Dry run mode - no files will be modified

Would modify: ./src/example.txt
--- a/./src/example.txt
+++ b/./src/example.txt
@@ -1 +1 @@
-Hello world
+Goodbye world

Processed 5 files, 1 modified

Multiple Dictionaries

You can define multiple dictionaries in your config for different replacement scenarios:

{
  "dictionaries": {
    "encode": {
      "secret": "s3cr3t",
      "password": "p4ssw0rd"
    },
    "localize_fr": {
      "Hello": "Bonjour",
      "Goodbye": "Au revoir"
    }
  }
}

Select which dictionary to use with --dict-name:

textswap -f ./src -d 1 -n encode
textswap -f ./src -d 1 -n localize_fr

Troubleshooting

"Invalid JSON in config file"

Your config file has a syntax error. Common issues:

  • Missing commas between items
  • Trailing commas (not allowed in JSON)
  • Unquoted strings

Use a JSON validator to check your config.

"Config must contain a 'dictionaries' object"

Your config file is missing the required dictionaries key:

{
  "dictionaries": {
    "my_dict": {"find": "replace"}
  }
}

Files being skipped

Files are skipped for these reasons (shown in output):

  • Not UTF-8 encoded: Binary files or files with different encoding
  • Permission denied: No read/write access to the file

No files modified

Check that:

  1. Your search terms exactly match the file content (case-sensitive)
  2. Files aren't being filtered by ignore rules
  3. The target folder contains text files

Overlapping or swapped replacements

All replacements happen in a single pass, longest key first:

  • Overlapping keys (e.g., "hello" and "hello world"): the longest key wins wherever it matches.
  • Replaced text is never re-replaced, so {"cat": "dog", "dog": "wolf"} turns "cat" into "dog" (not "wolf").
  • Two names can be swapped safely: {"foo": "bar", "bar": "foo"} exchanges them in one run.

When renaming identifiers, add --whole-words so a key like cat doesn't match inside category or concat.

Reverse direction with duplicate values

Direction 2 inverts the dictionary (values become keys). If two keys map to the same value, only the last mapping survives the inversion — a warning is printed when this happens.

Use Cases

  • Encoding/decoding: Obfuscate or de-obfuscate text in files
  • Localization: Batch replace text for different languages
  • Refactoring: Rename variables, functions, or classes across a codebase
  • Template substitution: Replace placeholders with actual values
  • Migration: Update deprecated API calls or import paths

Encoding

All files are read and written as UTF-8. Files that cannot be decoded as UTF-8 (binary files, files with other encodings) are automatically skipped and reported in the output.

License

GPL v3

Metadata

Release files for textswap 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for textswap 0.4.0
File Size Uploaded
textswap-0.4.0.tar.gz 31.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for textswap 0.4.0
File Interpreter ABI Platform
textswap-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 56.1 kB

Release files / textswap-0.4.0.tar.gz

Download URL textswap-0.4.0.tar.gz
Size 31.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8170644eb1a5657aff52a4905cb3b005017d925ed70a0f67180bfba540ac0daf
BLAKE2b-256 checksum
How to use checksums
53124a116a303d931ac769caed90243d75a859cc4006c1af14e1f07713f2b4ee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 15, 2026.

Transparency log

Release files / textswap-0.4.0-py3-none-any.whl

Download URL textswap-0.4.0-py3-none-any.whl
Size 24.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d8247be87b3b0f9bdd3f8a8498f44d7f77e5995ac4da2906818191ad34f7f93b
BLAKE2b-256 checksum
How to use checksums
141849100fa9383b00fc0e6e63e3ec27f97c1ddca0d4b65fa995551a1f0d91c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page