如何在满足条件的情况下添加字符串之间的字符

4
  • 如果字符串中含有 %20,则需要将其替换为 OR,例如 abc %20 def。期望输出 --> '*abc* OR *def*'
  • 如果字符串中含有逗号,则需要将其替换为 OR,例如 abc,def。期望输出 --> '*abc* OR *def*'
  • 字符串 = 'abc def':需要更新每个字符串的开头和结尾,并用 * 替换空格并使用 OR。期望输出 --> '*abc* OR *def*'
  • 字符串 = 'abc or def'、'abc+def'、'abc + def'、'abc OR def':如果字符串中存在 OR 或 +,则需要进行更新。期望输出 --> '*abc* OR *def*'
  • 字符串 = 'abc&def'、'abc & def'、'abc and def'、'abc AND def':如果字符串中存在 AND 或 &,则需要进行更新。期望输出 --> '*abc* AND *def*'
  • 字符串 = 'abc':期望输出 --> '*abc*'
  • 字符串 = 'abc def ghi':期望输出 --> '*abc* OR *def* OR *ghi*'
  • 所有标点符号都必须被替换

以下是代码:

import re
def format_search_value(search_value_1):
    punctuations = '''!()[]{};:"\,<>./?@#%^*~'''
    search_value_1 = search_value_1.replace('+', ' ')
    #if %20 there in the string it has to replace with OR, abc %20 def
    search_value_1 = re.sub('^(%20)+$', '%20', search_value_1)
    search_value = ""
    for char in search_value_1:
        if char not in punctuations:
            search_value = search_value + char
    search_expression = ','.join([f'*{word.strip()}*' for word in search_value.split(',')])
    search_expression = re.sub(' +', ' ', search_expression.replace('%20', ' '))
    search_expression = ','.join([f'*{word}*' for word in search_expression.split(' ')])
    search_parameter = search_expression.replace('%20', ' OR ').replace(',', ' OR ') \
        .replace('and', 'AND').replace('+', 'OR').replace('or', 'OR').strip()
    search_parameter = search_parameter.replace('**', '*')
    return search_parameter
format_search_value('abc or def')

我只在输入“abc def”且查询条件为'*abc* OR *def*'时才得到正确的输出。


已更新预期输出,堆栈溢出无法在单词中找到*,因此我已经明确添加了`到预期输出中,对造成的不便表示抱歉。 - sim
你想要如何替换除加号以外的所有标点符号? - Pubudu Sitinamaluwa
3个回答

6

在查看了Kraigolas和Will提供的出色答案之后,我尝试了一种只需要一个正则表达式的不同方法。

输入(借用自Will的回答 :D)

import re

test_cases = (
    'abc %20 def',
    'abc %20 def',
    'abc or def',
    'abc OR def',
    'abc+def',
    'abc + def',
    'abc&def',
    'abc & def',
    'abc AND def',
    'abc and def',
)

以下为包含5个模式组的正则表达式匹配规则。

group1: (\w+)\s? 捕获第一个空格前的所有字母。

group2: ((or|OR|\+|%20)|(&|and|AND)) group3和group4的封装组(这是创建一个正则表达式的关键)。

group3: (or|OR|\+|%20) 捕获or, OR, +, %20

group4: (&|and|AND) 捕获&, and, AND

group5: \s?(\w+) 捕获最后一个空格后面的所有字母。

请注意,\s? 捕获一个或零个空格。

pattern = re.compile(r'(\w+)\s?((or|OR|\+|%20)|(&|and|AND))\s?(\w+)')

按照以下格式格式化字符串。 如果存在第三组则替换为OR。否则替换为AND。(请注意,当第三组为空时,第四组不为空,反之亦然。)

def format_value(text):
    match = pattern.match(text)
    if match is not None and match.group(3):
        return pattern.sub(r'*\1* OR *\5*', text)
    else:
        return pattern.sub(r'*\1* AND *\5*', text)

for x in test_cases:
    print(format_value(x))

输出

*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* AND *def*
*abc* AND *def*
*abc* AND *def*
*abc* AND *def*

编辑 为了捕获abc def ghi,这里有一个小技巧。

创建另一个模式来捕获空格。这将不会捕获已经由*符号包围的格式化字符串,因为我正在寻找由两个字母字符包围的空格。

space_pattern = re.compile(r'(\w)(\s)(\w)')

通过去除前后的星号更新格式值的方法。

def format_value(text):
    match = pattern.match(text)
    if match is not None and match.group(3):
        return pattern.sub(r'\1* OR *\5', text)
    else:
        return pattern.sub(r'\1* AND *\5', text)

重新格式化字符串并在开头和结尾添加星号如下。
for x in test_cases:
    formatted_value = format_value(x)
    print("*" + space_pattern.sub(r'\1* OR *\3', formatted_value) + "*")

输出

*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* AND *def*
*abc* AND *def*
*abc* AND *def*
*abc* AND *def*
*abc*
*abc* OR *def* OR *ghi*

你能帮忙实现另一个场景吗? - sim
如果我传递单个字符串或两个以上的字符串,它不起作用,例如:
  • 单个 = 'abc',期望输出 --> 'abc'
  • 两个或更多 = 'abc def ghi',期望输出 --> 'abc OR def OR ghi'
- sim
@sim 我已经在我的帖子中添加了一个编辑。请检查一下是否完全解决了你的问题。 - Pubudu Sitinamaluwa

3

编辑

此答案是在问题更新前创建的,在更新后显示需要用 *包围abcdef的期望输出。随意借鉴它来创建一个与新问题更相关的答案。

原回答

这实际上可以在几行代码中完成。我将替换所有匹配项(而不仅仅是一次出现):

import re

text = """
abc %20 def
abc %20 def
abc or def
abc+def
abc + def

abc&def
abc & def
abc AND def
"""

or_pattern = re.compile("\s*(%20|\+)\s*|\s+or\s+")
text = or_pattern.sub(" OR ", text)

and_pattern = re.compile("\s*&\s*|\s+AND\s+")
text = and_pattern.sub(" AND ", text)

text的输出现在是:

abc OR def
abc OR def
abc OR def
abc OR def
abc OR def

abc AND def
abc AND def
abc AND def

或模式

\s*(%20|\+)\s*|\s+or\s+

这个被正则表达式“或”|分成两部分:
\s*(%20|\+)\s*
  • \s*表示匹配0个或多个空格(为了更严谨,你可以使用s{0,1}只匹配0个或1个空格)
  • (%20|\+)表示在两个\s*之间匹配(并捕获,这是正则表达式|的需要)%20+中的任意一个字符。

and

\s+or\s+

这部分被分开是因为我们需要在每个or两侧至少有一个空格,否则door将被替换为do OR

大小写不敏感

在您的情况下,您可能还希望oROr匹配,这种情况下您可以使用re.compile("pattern", re.IGNORECASE)


1
我已更新了预期输出,堆栈溢出无法在单词中找到 *。 - sim
1
所以我必须在期望的输出中显式添加反引号,对造成的不便感到抱歉。 - sim

2

根据Kraigolas提供的内容,这里是解决您问题的方案:

import re

or_pattern = re.compile(r'\s*(%20|\+)\s*|\s+or\s+', re.IGNORECASE)
and_pattern = re.compile(r'\s*&\s*|\s+and\s+', re.IGNORECASE)
operand_pattern = re.compile(r'(\w+)\s*(OR|AND)\s*(\w+)')

def format_search_value(search_value):
    search_value = or_pattern.sub(' OR ', search_value)
    search_value = and_pattern.sub(' AND ', search_value)
    return operand_pattern.sub(r'*\1* \2 *\3*', search_value)

它能够完成Kraigolas答案的所有操作,并使用operand_pattern在操作数周围加上星号。它在模式中使用了3个捕获组:
  1. 第一个操作数:(\w+)
  2. 运算符:(OR|AND)
  3. 第二个操作数:(\w+)
  4. 这三个捕获值随后使用特殊值\1\2\3插入到带有星号的替换字符串中:*\1* \2 *\3*

用法:

test_cases = (
    'abc %20 def',
    'abc %20 def',
    'abc or def',
    'abc OR def',
    'abc+def',
    'abc + def',
    'abc&def',
    'abc & def',
    'abc AND def',
    'abc and def',
)

for search_value in test_cases:
    print(format_search_value(search_value))

输出:

*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* OR *def*
*abc* AND *def*
*abc* AND *def*
*abc* AND *def*
*abc* AND *def*

你能检查一下输出吗?我得到了 abc OR def,但是没有 * 在它们之间。 - sim
你能检查一下你的代码吗?我觉得你忘记复制粘贴了。 - sim
你能帮忙实现另一个场景吗? - sim
如果我传递单个字符串或多于两个字符串,它不起作用, 单个 = 'abc',:预期输出--> 'abc',更多的双倍 = 'abc def ghi':预期输出--> 'abc'或'def'或'ghi' - sim
2
@sim 如果你有额外的问题,应该提出新的问题,而不是更新相同的问题。 - Will Da Silva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接