I would suggest using replace along with map
Example:
my_list = ['BASE', 'BASE xBU xPY', 'BU GROUP REL', 'PY REL']
converter = lambda x: x.replace(' ', '_')
my_list = list(map(converter, my_list))
my_list
['BASE', 'BASE_xBU_xPY', 'BU_GROUP_REL', 'PY_REL']
Answer from Kuldeep Singh Sidhu on Stack Overflowpython - How to replace whitespaces with underscore? - Stack Overflow
python - Fastest way to replace space for underscore for a list of words in text - Stack Overflow
modelbuilder - Replace occasional Space with Underscore using Python parser of ArcGIS Field Calculator? - Geographic Information Systems Stack Exchange
Replace space with underscore using python - Stack Overflow
You don't need regular expressions. Python has a built-in string method that does what you need:
mystring.replace(" ", "_")
Replacing spaces is fine, but I might suggest going a little further to handle other URL-hostile characters like question marks, apostrophes, exclamation points, etc.
Also note that the general consensus among SEO experts is that dashes are preferred to underscores in URLs.
import re
def urlify(s):
# Remove all non-word characters (everything except numbers and letters)
s = re.sub(r"[^\w\s]", '', s)
# Replace all runs of whitespace with a single dash
s = re.sub(r"\s+", '-', s)
return s
# Prints: I-cant-get-no-satisfaction"
print(urlify("I can't get no satisfaction!"))
It may be better to split the words, mapping the words from the start of the phrase to the full phrase, if you need the largest, instead of checking every item in the dict you just need to sort the phrases that appear by length:
from collections import defaultdict
def get_phrases(fle):
phrase_dict = defaultdict(list)
with open(fle) as ph:
for line in map(str.rstrip, ph):
k, _, phr = line.partition(" ")
phrase_dict[k].append(line)
return phrase_dict
from itertools import chain
def replace(fle, dct):
with open(fle) as f:
for line in f:
phrases = sorted(chain.from_iterable(dct[word] for word in line.split()
if word in dct) ,reverse=1, key=len)
for phr in phrases:
line = line.replace(phr, phr.replace(" ", "_"))
yield line
Output:
In [10]: cat out.txt
This is a sentence that contains multiple phrases that I need to replace with phrases with underscores, e.g. social political philosophy with political philosophy under the branch of philosophy and some computational linguistics where the cognitive linguistics and psycho cognitive linguistics appears with linguistics
In [11]: cat phrases.txt
cognitive linguistics
psycho cognitive linguistics
socio political philosophy
political philosophy
computational linguistics
linguistics
philosophy
social political philosophy
In [12]: list(replace("out.txt",get_phrases("phrases.txt")))
Out[12]: ['This is a sentence that contains multiple phrases that I need to replace with phrases with underscores, e.g. social_political_philosophy with political_philosophy under the branch of philosophy and some computational_linguistics where the cognitive_linguistics and psycho_cognitive_linguistics appears with linguistics']
A few other versions:
def repl(x):
if x:
return x.group().replace(" ", "_")
return x
def replace_re(fle, dct):
with open(fle) as f:
for line in f:
spl = set(line.split())
phrases = chain.from_iterable(dct[word] for word in spl if word in dct)
line = re.sub("|".join(phrases), repl, line)
yield line
def replace_re2(fle, dct):
cached = {}
with open(fle) as f:
for line in f:
phrases = tuple(chain.from_iterable(dct[word] for word in set(line.split()) if word in dct))
if phrases not in cached:
r = re.compile("|".join(phrases))
cached[phrases] = r
line = r.sub(repl, line)
else:
line = cached[phrases].sub(repl, line)
yield line
I would make a regex of your Dictionary to match the data.
Then on the replacement side, use a callback to replace spaces with _.
I estimate it would take less than 3 hours to do the whole thing.
Fortunately there is a Ternary Tool (Dictionary) regex generator.
To generate the regex and for what is shown below, you'll need the Trial
version of RegexFormat 7
Some links:
Screenshot of tool
TernaryTool(Dictionary) - Text version Dictionary samples
A 175,000 word Dictionary Regex
You basically generate your own Dictionary
by dropping in the strings you want to find, then press the Generate button.
Then all you have to do is read in 5 MB chunks and do a find/replace using the
regex, then append it to the new file.. rinse repeat.
Pretty simple really.
Based on your sample (above) this is an estimate of the time it would take
to complete 10 Billion lines.
This analysis is based on using a benchmark that was run on your sample input using the generated regex (below).
19 lines (@ 3600 chars)
Completed iterations: 50 / 50 ( x 1000 )
Matches found per iteration: 5
Elapsed Time: 4.03 s, 4034.28 ms, 4034278 µs
////////////////////////////
3606 chars
x 50,000
------------
180,300,000 (chars)
or
20 lines
x 50,000
------------
1,000,000 (lines)
=========================
10,000,000,000 lines
/
1,000,000 (lines) per 4 seconds
-----------------------------------------
40,000 seconds
/
3600 secs per hour
-------------------------
11 hours
////////////////////////////
However, if you read in and process 5 megabyte chunks
(as a single string) it will reduce the engine overhead
and have the time down to 1-3 hours.
This is the generated regex for your sample Dictionary (compressed):
\b(?:c(?:linical |o(?:gnitive |mp(?:arative |ound[ ]morphology|utational[ ]linguistics)|rrelation|sm(?:etic[ ]dentistry|o(?:graphy|logy)))|r(?:anio(?:logy|metry)|iminology|y(?:o(?:biology|genics|nics)|ptanalysis|stallography))|urvilinear[ ]correlation|y(?:bernetics|to(?:genetics|logy)))|de(?:ixis|mography|nt(?:al |istry))|p(?:hilosophy|olitical[ ]philosophy))\b
(Note that the space separation are generated as [ ] per space.
If you want to change it to a quantified class, just run a
find (?:\[ \])+ and replace with whatever you want.
For example \s+ or [ ]+)
Here it is Formatted:
\b
(?:
c
(?:
linical [ ]
(?: anatomy | psychology )
| o
(?:
gnitive [ ]
(?: neuroscience | psychology | science )
| mp
(?:
arative [ ]
(?: anatomy | psychology )
| ound [ ] morphology
| utational [ ] linguistics
)
| rrelation
| sm
(?:
etic [ ] dentistry
| o
(?: graphy | logy )
)
)
| r
(?:
anio
(?: logy | metry )
| iminology
| y
(?:
o
(?: biology | genics | nics )
| ptanalysis
| stallography
)
)
| urvilinear [ ] correlation
| y
(?:
bernetics
| to
(?: genetics | logy )
)
)
| de
(?:
ixis
| mography
| nt
(?:
al [ ]
(?: anatomy | surgery )
| istry
)
)
| p
(?: hilosophy | olitical [ ] philosophy )
)
\b
Adding 10,000 phrases is very easy and the regex is no bigger than
the amount of bytes in the phrases plus a bit of overhead to interlace
the regex.
A final note. You can reduce the time even further by only generating the
regex on phrases.. that is only words separated by horizontal whitespace.
And, be sure to pre-compile the regex. Only have to do this once.
You don't necessarily have to define a function for this one. Try this:
str(!PlaceName!).replace(' ', '')
The "not defined" error is related to the lack of quotes around the NoSpace1. This could be from the % on either side of the Value. Your expression should be
ReplaceName(!Placename!)
You do not need the field calculator for replace at all.
You can just use the Find & Replace tool which is accessed from the attribute-table which has the search/replace function the same way as in Excel, for example.
It also works for all columns simultaneously or can be set to search for whole values etc.

Here's a generic approach that should work for you:
teststring = 'hello world this is just a test. don\'t mind me 123.'
# replace multiple spaces with one space
while ' ' in teststring:
teststring = teststring.replace(' ', ' ')
# replace space with underscore (_)
teststring = teststring.replace(' ', '_')
print(teststring)
assert teststring == "hello_world_this_is_just_a_test._don't_mind_me_123." # True
Using a file example:
fname = 'mah_file.txt'
with open(fname) as in_file:
contents = in_file.read()
while ' ' in contents:
contents = contents.replace(' ', ' ')
# write updated contents back to file
with open(fname, 'w') as out_file:
out_file.write(contents.replace(' ', '_'))
This opens the files, reads line by line, splits the line into two parts, and combines the two parts with an underscore. I stored it in a list that you can use to do your next step.
with open('nog_rename_update.txt') as f:
new_list = []
for line in f:
# split the line
split = line.split()
new_list.append(split[0]+"_"+split[1])
# print the list to see results
print(new_list)
#
# add code to loop through the new list and to write to a file
#