【问题标题】:String Find/Replace Algorithm字符串查找/替换算法
【发布时间】:2023-03-12 23:09:02
【问题描述】:

我希望能够在一个字符串中搜索各种单词,当我找到一个时,我想将那个点的字符串分成 3 部分(左、匹配、右),匹配的文本将被排除,并且该过程将继续使用新字符串 left+right。

现在,一旦我完成了所有匹配项,我需要通过在删除匹配的单词(或替换它们)处重新插入匹配的单词(或替换它们)来反转该过程。我从来没有在我的任何搜索中真正找到我想要的东西,所以我想我会在 SO 上征求意见。

如果这个问题需要进一步描述,请告诉我。

顺便说一句 - 目前,我有一个非常糟糕的算法,它用唯一的字符串标记替换匹配的文本,然后在所有匹配完成后用替换文本替换标记以进行适当的匹配。

这是目标:

one two three four five six 

将匹配“三”替换为 foo(记住我们找到了三个,以及我们在哪里找到的)

one two four five six
       |
     three

匹配“二四”并防止它被任何东西匹配(为清楚起见进行了编辑)

one five six
   |
 two four 
       |
     three

此时,您无法匹配例如“一二”

已找到所有匹配项,现在将它们的替换项放回(以相反的顺序)

one two four five six
       |
     three


one two foo four five six

有什么意义?防止一个匹配的替换文本被另一个模式匹配。 (所有模式在同一时间以相同的顺序运行每个处理的字符串)

我不确定语言是否重要,但在这种情况下我使用的是 Lua。

我会尝试改写,我有一个我想在给定字符串中找到的模式列表,如果我找到一个,我想删除字符串的那部分,这样它就不会被其他任何东西匹配,但我想跟踪我在哪里找到它,这样一旦我尝试匹配我的模式列表,我就可以在那里插入替换文本

这是一个相关的问题:

Shell script - search and replace text in multiple files using a list of strings

【问题讨论】:

  • 那么算法完成后,字符串和你留下的一样吗?为什么首先需要删除字符串?你对这个结果做什么?可能有更简单的解决方案。请发布您使用的语言。
  • 继续左+右到底是什么意思?假设原文是“abcdefgh”,而你的两个“词”是“cd”和“bef”,你会先拆分成“ab”-“cd”-“efgh”,然后在“abefgh”中搜索,然后找到“bef”,拆分成“a”-“bef”-“gh”,然后继续“agh”,没有找到?
  • 好的,我用图表来改进问题
  • 你怎么知道在你的例子中你得到的是“一巴五六”还是“一富五六”?关于其他匹配项中的匹配项的去向是否有明确的规则?
  • 搜索词匹配将如何进行?术语“二四”跳过了原始输入中的一个词。 (我想我可能不得不删除我原来的答案......哈哈)

标签: algorithm replace


【解决方案1】:

您的算法描述不清楚。没有确切的规则应该重新插入提取的令牌。

这是一个例子:

  1. 在“一二三四五六”中查找“三”
  2. 选择这两者之一以获得“foo bar”作为结果:

    一个。将“一二”替换为“foo”,将“四五六”替换为“bar”

    b.用“foo bar”替换“一二四五六”

  3. 在第 2 步生成的字符串 'foo bar' 中插入 'three'

在第 3 步,'three' 是在 'bar' 之前还是之后?

一旦您想出了重新插入的明确规则,您就可以轻松地将算法实现为递归方法或具有替换堆栈的迭代方法。

【讨论】:

  • 我在你发帖时修复了这个例子,有点不清楚你是对的。
【解决方案2】:

鉴于问题的结构,我可能会尝试基于二叉树的算法。

【讨论】:

  • 我的答案是根据问题的原始版本发布的......我仍然想解决这个问题,但到目前为止我写的可能不是最好的方法(因为似乎还没有人完全理解这个问题)。
【解决方案3】:

伪代码:

for( String snippet in snippets )
{
    int location = indexOf(snippet,inputData);
    if( location != -1)
    {
        // store replacement text for a found snippet on a stack along with the
        // location where it was found
        lengthChange = getReplacementFor(snippet).length - snippet.length;
        for each replacement in foundStack
        {
            // IF the location part of the pair is greater than the location just found
            //Increment the location part of the pair by the lengthChange to account
            // for the fact that when you replace a string with a new one the location
            // of all subsequent strings will be shifted 
        }

        //remove snippet
        inputData.replace(snippet, "");
    }
}

for( pair in foundStack )
{
    inputData.insert( pair.text, pair.location);
}

这基本上只是按照您在问题描述中所说的那样做。逐步执行该算法,将所有内容与其所在位置放在一个堆栈中。您使用堆栈,因此当您在后半部分重新插入时,它会以相反的顺序发生,以便存储的“位置”适用于 inputString 的当前状态。

已编辑,可能会解决评论者的批评。第一个中对块的评论是否说明了您的批评,还是在某些情况下仍然存在错误?

【讨论】:

  • 除非由于后续替换,位置可以在字符串之外。或者它可能位于替换字符串的中间。
  • 我编辑了一个可能解决您批评的潜在解决方案。你认为它会起作用吗?
  • 即使这确实有效,但经过进一步考虑,我认为递归执行此操作会更好。
  • 我倾向于同意 - 假设匹配数保持较小,递归似乎是解决此问题的好方法。
  • 好吧,我尝试递归地执行此操作,但找不到解决相同问题的好方法,即后来的替换搞砸了早期替换的插入位置,所以我倾向于回到这个,我原来的做法。我最初的信封测试发现它至少有效。