Tl;dr
Based on replies by @jonrsharpe and @juanpa.arrivillaga, I came up with the following functions to be the best answer:
open_chars = "([{<"
close_chars = ")]}>"
swap_direction_table = str.maketrans(open_chars+close_chars, open_chars+close_chars)
def to_opening(text):
for ch_close, ch_open in zip(close_chars, open_chars):
if ch_close in text:
text = text.replace(ch_close, ch_open)
return text
def to_closing(text):
for ch_open, ch_close in zip(open_chars, close_chars):
if ch_open in text:
text = text.replace(ch_open, ch_close)
return text
def swap_direction(text):
return s.translate(swap_direction_table)
Additional Testing
For the sake of thoroughness, I did a few additional tests. Below is the complete list of functions I tried, organized by technique.
# sandbox.py
open_chars = "([{<"
close_chars = ")]}>"
to_open_table = str.maketrans(close_chars, open_chars)
to_close_table = str.maketrans(open_chars, close_chars)
swap_direction_table = str.maketrans(open_chars+close_chars, close_chars+open_chars)
def to_opening_tr(text):
return text.translate(to_open_table)
def to_closing_tr(text):
return text.translate(to_close_table)
def swap_direction_tr(text):
return text.translate(swap_direction_table)
def to_opening_tb(text):
return text.translate(str.maketrans(close_chars, open_chars))
def to_closing_tb(text):
return text.translate(str.maketrans(open_chars, close_chars))
def swap_direction_tb(text):
return text.translate(str.maketrans(open_chars+close_chars, close_chars+open_chars))
def to_opening_r(text):
return text.replace(")", "(").replace("]", "[").replace("}", "{").replace(">", "<")
def to_closing_r(text):
return text.replace("(", ")").replace("[", "]").replace("{", "}").replace("<", ">")
def to_opening_fr(text):
for ch_close, ch_open in zip(close_chars, open_chars):
if ch_close in text:
text = text.replace(ch_close, ch_open)
return text
def to_closing_fr(text):
for ch_open, ch_close in zip(open_chars, close_chars):
if ch_open in text:
text = text.replace(ch_open, ch_close)
return text
def swap_direction_fr(text):
for ch_open, ch_close in zip(open_chars, close_chars):
if ch_open in text and ch_close in text:
text = text.replace(ch_open, '$temp$').replace(ch_close, ch_open).replace('$temp$', ch_close)
elif ch_open in text:
text = text.replace(ch_open, ch_close)
elif ch_close in text:
text = text.replace(ch_close, ch_open)
return text
Here are the results from the timeit
library:
to_opening_tr: 500000 loops, best of 5: 622 nsec per loop
to_opening_tb: 500000 loops, best of 5: 784 nsec per loop
to_opening_r: 1000000 loops, best of 5: 293 nsec per loop
to_opening_fr: 500000 loops, best of 5: 600 nsec per loop
to_closing_tr: 500000 loops, best of 5: 622 nsec per loop
to_closing_tb: 500000 loops, best of 5: 800 nsec per loop
to_closing_r: 1000000 loops, best of 5: 328 nsec per loop
to_closing_fr: 500000 loops, best of 5: 582 nsec per loop
swap_direction_tr: 500000 loops, best of 5: 569 nsec per loop
swap_direction_tb: 200000 loops, best of 5: 998 nsec per loop
swap_direction_fr: 500000 loops, best of 5: 937 nsec per loop
I used the following PowerShell script to automate the process a bit:
$test_str = "'abcd{1>2(3]'"
# $test_str = "'abcd{1>2(3]abcd}1>)))3[[[[abasdh[[[[[[[['" # Alternate string to try
Write-Host "to_opening_tr: " -NoNewline
python -m timeit -s "import sandbox" "sandbox.to_opening_tr($test_str)"
Write-Host "to_opening_tb: " -NoNewline
python -m timeit -s "import sandbox" "sandbox.to_opening_tb($test_str)"
Write-Host "to_opening_r: " -NoNewline
python -m timeit -s "import sandbox" "sandbox.to_opening_r($test_str)"
Write-Host "to_opening_fr: " -NoNewline
python -m timeit -s "import sandbox" "sandbox.to_opening_fr($test_str)"
Write-Host ""
Write-Host "to_closing_tr: " -NoNewline
python -m timeit -s "import sandbox" "sandbox.to_closing_tr($test_str)"
Write-Host "to_closing_tb: " -NoNewline
python -m timeit -s "import sandbox" "sandbox.to_closing_tb($test_str)"
Write-Host "to_closing_r: " -NoNewline
python -m timeit -s "import sandbox" "sandbox.to_closing_r($test_str)"
Write-Host "to_closing_fr: " -NoNewline
python -m timeit -s "import sandbox" "sandbox.to_closing_fr($test_str)"
Write-Host ""
Write-Host "swap_direction_tr: " -NoNewline
python -m timeit -s "import sandbox" "sandbox.swap_direction_tr($test_str)"
Write-Host "swap_direction_tb: " -NoNewline
python -m timeit -s "import sandbox" "sandbox.swap_direction_tb($test_str)"
Write-Host "swap_direction_fr: " -NoNewline
python -m timeit -s "import sandbox" "sandbox.swap_direction_fr($test_str)"
I don't want to hear about how my PowerShell sucks ;)
The algorithms with the best times in each category are the ones in the Tl;dr above. The results seem to be consistent among a few different sample strings I've tried.