You can do it using str.translate and string.maketrans which will be the most efficient approach not chaining calls etc..:
In [6]: from string import maketrans
In [7]: s = "Hello----..... World"
In [8]: table = maketrans(' .-',"___")
In [9]: print(s.translate(table))
Hello_____________World
The timings:
In [12]: %%timeit
....: s = "Hello----..... World"
....: table = maketrans(' .-',"___")
....: s.translate(table)
....:
1000000 loops, best of 3: 1.14 µs per loop
In [13]: timeit s.replace('-','_').replace('.', '_').replace(' ', '_')
100000 loops, best of 3: 2.2 µs per loop
In [14]: %%timeit
text = "Hello----..... World"
for ch in [' ', '.', '-']:
if ch in text:
text = text.replace(ch,'_')
....:
100000 loops, best of 3: 3.51 µs per loop
In [18]: %%timeit
....: s = "Hello----..... World"
....: re.sub(r"[ .-]", "_", s)
....:
100000 loops, best of 3: 11 µs per loop
Even pre-compiling the pattern leaves around 10µs so the regex is by far the least efficient approach.
In [20]: patt= re.compile(r"[ .-]")
In [21]: %%timeit
s = "Hello----..... World"
patt.sub( "_", s)
....:
100000 loops, best of 3: 9.98 µs per loop
Pre creating the table gets us down to nanoseconds:
In [22]: %%timeit
s = "Hello----..... World"
s.translate(table)
....:
1000000 loops, best of 3: 590 ns per loop