UPDATED SOLUTION (2025 NOV 21):
The previous solution is rigid and it does not work if a replacement string input preceding another replacement string input (in this case the first replacement string) includes a literal NOUN string(s). This below solution, uses re.finditer() to first get the indexes of all the literal NOUN strings. And, the requests matching replacement strings. It then replaces literal NOUN strings with the replacement text from user input, starting from the end of the text string. Also added word boundary syntax (\b) into the regex to make sure we do not replace the NOUN in strings like PRONOUN, etc.
PYTHON:
import re
text_file_content ='ADJECTIVE panda walked to the [1]:NOUN:[1] and then VERB. A nearby [2]:NOUN:[2] was unaffected by these events.ADJECTIVE panda walked to the [3]:NOUN:[3] and then VERB. A nearby [4]:NOUN:[4] was unaffected by these events.ADJECTIVE panda walked to the [5]:NOUN:[5] and then VERB. A nearby [6]:NOUN:[6] was unaffected by these events.ADJECTIVE panda walked to the [7]:NOUN:[7] and then VERB. A nearby [8]:NOUN:[8] was unaffected by these events.'
print(text_file_content)
nouns_found = re.search(r'\bNOUN\b', text_file_content)
if nouns_found != None:
# Find all NOUNs
matches = re.finditer(r'\bNOUN\b', text_file_content)
noun_indexes = list() # Initialize
# Get start and end index for each NOUN
for match in matches:
index_span = match.span() # (start_index, end_index)
noun_indexes.append(index_span)
number_of_nouns = len(noun_indexes) # NOUN count (from text)
# Reverse the index list with elements (start_index, end_index)
noun_indexes_reversed = sorted(noun_indexes, key=lambda x: x[0], reverse=True)
print(f"Number of NOUN strings: {number_of_nouns}")
replacement_strings = list() # Initialize
# Get the replacements from user:
for i in range(number_of_nouns):
input_string = input(f'Enter a noun ({str(i+1)}): ')
replacement_strings.append((i, input_string))
# Reverse the order of the replacement strings
replacement_strings_reversed = sorted(replacement_strings, key=lambda x: x[0], reverse=True)
# Replace the NOUN with the matching replacement, starting from the end of the string.
for i, string in enumerate(replacement_strings_reversed):
text_file_content = text_file_content[:noun_indexes_reversed[i][0]] + string[1] + text_file_content[noun_indexes_reversed[i][1]:]
# Print result
print(text_file_content)
OUTPUT (TERMINAL) Text before and after:
ADJECTIVE panda walked to the [1]:NOUN:[1] and then VERB. A nearby [2]:NOUN:[2] was unaffected by these events.ADJECTIVE panda walked to the [3]:NOUN:[3] and then VERB. A nearby [4]:NOUN:[4] was unaffected by these events.ADJECTIVE panda walked to the [5]:NOUN:[5] and then VERB. A nearby [6]:NOUN:[6] was unaffected by these events.ADJECTIVE panda walked to the [7]:NOUN:[7] and then VERB. A nearby [8]:NOUN:[8] was unaffected by these events.
Number of NOUN strings: 8
Enter a noun (1): (STRING 1)
Enter a noun (2): (STRING 2)
Enter a noun (3): (STRING 3)
Enter a noun (4): (STRING 4)
Enter a noun (5): (STRING 5)
Enter a noun (6): (STRING 6)
Enter a noun (7): (STRING 7)
Enter a noun (8): (STRING 8)
ADJECTIVE panda walked to the [1]:(STRING 1):[1] and then VERB. A nearby [2]:(STRING 2):[2] was unaffected by these events.ADJECTIVE panda walked to the [3]:(STRING 3):[3] and then VERB. A nearby [4]:(STRING 4):[4] was unaffected by these events.ADJECTIVE panda walked to the [5]:(STRING 5):[5] and then VERB. A nearby [6]:(STRING 6):[6] was unaffected by these events.ADJECTIVE panda walked to the [7]:(STRING 7):[7] and then VERB. A nearby [8]:(STRING 8):[8] was unaffected by these events.
OLD ANSWER: This solution works, however, it is rigid and does not allow literal NOUN to be in the user input. (In this case the first user input). Provided a dynamic solution above that allows any string input from user.
count=1 fixes the issue.
The count parameter requires a keyword argument.
SYNTAX (Corrected 2025 NOV 21)
re.sub(pattern, repl, string, *, count=0, flags=0)
Python Docs Ref: https://docs.python.org/3/library/re.html#re.sub (1)
(1) The relevant quote from the linked reference: Deprecated since version 3.13: Passing count and flags as positional arguments is deprecated. In future Python versions they will be keyword-only parameters.
PYTHON
import re
TextFileContent ='ADJECTIVE panda walked to the NOUN and then VERB. A nearby NOUN was unaffected by these events.'
SpecialRegexes_NOUN = re.compile('NOUN')
if SpecialRegexes_NOUN.search(TextFileContent) != None:
ForGroup2 = input('Enter a noun: ')
ForGroup3 = input('Enter a noun: ')
TextFileContent = re.sub('NOUN', ForGroup2, TextFileContent, count=1)
TextFileContent = re.sub('NOUN', ForGroup3, TextFileContent, count=1)
print(TextFileContent)
OUTPUT (TERMINAL)
Enter a noun: BALLOON # User input
Enter a noun: BUTTERFLY # User input
ADJECTIVE panda walked to the BALLOON and then VERB. A nearby BUTTERFLY was unaffected by these events
printwork?1tocount=1to see if that fixes the deprecation warning.if) statements and keep minimal code that demonstrate the problem. (Note that on SO questions expected to show example code that demonstrates the single problem, reviewing of complete working code may be suitable for Code Review)count=1.