简体   繁体   English

如何从包含多个相似部分的字符串中仅替换子字符串的一部分?

[英]How to replace only one part of a sub string from a string containing more than one similar parts?

I might have not stated the question as what I would like to. 我可能没有将这个问题说成是我想要的。 Please consider below scenario. 请考虑以下情况。

Scenario: 场景:
I am implementing a Search/Replace functionality in my C# Win Form application. 我正在我的C#Win Form应用程序中实现搜索/替换功能。 This feature will have the option to replace a substring that "starts with" or "ends with" a certain value. 此功能可以选择替换“以...开头”或“以...结尾”某个值的子字符串。 For example: 例如:

  • A string contains "123ABCD" . 一个字符串包含"123ABCD" Replacing "123" with "XYZ" should produce: "XYZABCD" "XYZ"替换"123"应该产生: "XYZABCD"
  • A string contains "ABCD123" . 一个字符串包含"ABCD123" Replacing "123" with "XYZ" should produce: "ABCDXYZ" "XYZ"替换"123"应该产生: "ABCDXYZ"

Both of these features are working fine. 这两个功能都运行正常。 My problem is when the string contains "123ABCD123" . 我的问题是当字符串包含"123ABCD123" Both operations return the wrong value when using "XYZ" . 使用"XYZ"时,两个操作都返回错误的值。

  • "starts with" produces "XYZABCDXYZ" , instead of "XYZABCD" “以”开头“生成"XYZABCDXYZ" ,而不是"XYZABCD"
  • "ends with" produces "XYZABCDXYZ" instead of "ABCDXYZ" “以”结尾“生成"XYZABCDXYZ"而不是"ABCDXYZ"

Can anyone give me an idea how to achieve that? 任何人都可以告诉我如何实现这一目标吗?

Thanks !!! 谢谢 !!!

Code Snippet: 代码片段:

if (this.rbMatchFieldsStartedWith.Checked)
{
    if (caseSencetive)
    {
        matched = currentCellValue.StartsWith(findWhat);
    }
    else
    {
        matched = currentCellValue.ToLower().StartsWith(findWhat.ToLower());
    }
}
else if (this.rbMatchFieldsEndsWith.Checked)
{
    if (caseSencetive)
    {
        matched = currentCellValue.EndsWith(findWhat);
    }
    else
    {
        matched = currentCellValue.ToLower().EndsWith(findWhat.ToLower());
    }
}

if (matched)
{
    if (replace)
    {
        if (this.rbMatchWholeField.Checked)
        {
            currentCell.Value = replaceWith;
        }
        else
        {
            currentCellValue = currentCellValue.Replace(findWhat, replaceWith);
            currentCell.Value = currentCellValue;
        }
        this.QCGridView.RefreshEdit();
    }
    else
    {
        currentCell.Style.BackColor = Color.Aqua;
    }
}

This sounds like a good one for regular expressions . 对于正则表达式来说,这听起来很不错。

It is supported by .NET, and also has a replacement syntax. 它受.NET支持,并且还具有替换语法。

Implement the replacement method dependent on the search mode. 根据搜索模式实现替换方法。

Replace the line 更换线

currentCellValue = currentCellValue.Replace(findWhat, replaceWith);

with

if (this.rbMatchFieldsStartedWith.Checked)
{
    // target string starts with findWhat, so remove findWhat and prepend replaceWith
    currentCellValue = replaceWith + currentCellValue.SubString(findWhat.Length);
}
else
{
    // target string end with findWhat, so remove findWhat and append replaceWith.
    currentCellValue = currentCellValue.SubString(0, currentCellValue.Length - findWhat.Length) + replaceWith;
}

currentCell.Value = newValue;

I just want to try a replacement method without using regex. 我只想尝试不使用正则表达式的替换方法。
(Regex could be the right way to do it, but it was funny to find an alternative) (正则表达式可能是正确的方法,但找到替代方案很有趣)

void Main()
{
    string test = "123ABCD123";  // String to change
    string rep = "XYZ";          // String to replace
    string find = "123";         // Replacement string
    bool searchStart = true;     // Flag for checkbox startswith 
    bool searchEnd = true;       // Flag for checkbox endswith
    bool caseInsensitive = true; // Flag for case type replacement

    string result = test;         
    int pos = -1;
    int lastPos = -1;

    if(caseInsensitive == true)
    {
        pos = test.IndexOf(find, StringComparison.InvariantCultureIgnoreCase);
        lastPos = test.LastIndexOf(find, StringComparison.InvariantCultureIgnoreCase);
    }
    else
    {
        pos = test.IndexOf(find, StringComparison.Ordinal);
        lastPos = test.LastIndexOf(find, StringComparison.Ordinal);
    }

    result = test;
    if(pos == 0 && searchStart == true)
    {
        result = rep + test.Substring(find.Length);
    }
    if(lastPos != 0 && lastPos != pos && lastPos + find.Length == test.Length && searchEnd == true)
    {
        result = result.Substring(0, lastPos) + rep;
    }
    Console.WriteLine(result);
}

First off all let's trace your scenario assuming: 首先,我们假设:

  • string to work on is 123ABCD123 要处理的字符串是123ABCD123
  • starts with is checked. 开始时检查。
  • aim is to replace "123" with "XYZ" 目的是用“XYZ”代替“123”

by just reading your code. 只需阅读您的代码。 We hit if (this.rbMatchFieldsStartedWith.Checked) and which evaluates to true. 我们点击if (this.rbMatchFieldsStartedWith.Checked)并且评估为true。 So we step in that block. 所以我们介入那个区块。 We hit matched = currentCellValue.StartsWith(findWhat); 我们点击matched = currentCellValue.StartsWith(findWhat); and matched = true . matched = true We continue with if (matched) condition which also evaluates to true . 我们继续if (matched)条件也评估为true After that if (replace) evaluates to true . 之后if (replace)计算结果为true Finally we make the last decision with if (this.rbMatchWholeField.Checked) which evaluates to false so we continue with else block: 最后,我们用if (this.rbMatchWholeField.Checked)做出最后的决定,结果为false所以我们继续使用else块:

currentCellValue = currentCellValue.Replace(findWhat, replaceWith);
currentCell.Value = currentCellValue;

First line in this block replaces all the occurrences of findWhat with replaceWith , namely all the occurrences of 123 with XYZ. 在该块中第一行替换的所有出现findWhatreplaceWith ,123即所有出现与XYZ。 Of course this is not the desired behaviour. 当然,这不是理想的行为。 Instead of Replace you must use a function that replaces just the first or the last occurrence of the string according to the input of course. 而不是Replace您必须使用一个函数,根据当然的输入,只替换字符串的第一个或最后一个出现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM