How can I replace a string twice with oldValues ​​having the same text inside?

I am trying to take a block of text and scan it for a specific text (name) and turn it into a URL, specifically:

Block of text:

Chairman Joe Smith has announced a new plan to decrease expenditures by outsourcing the planning of the new dining hall. Smith states the current project managers do not have excess time to commit to this new project and this will be less costly than hiring a new or contract project manager.

Now what I'm trying to do is take any examples of Chairman Joe Smith or Joe Smith or Smith or Chairman Smith and link that to his profile / bio. Using whatever string methods I know of (string replace, string builder, add text before and after the corresponding line), I ran into a problem when scanning for Smith and then any other name.

If I try the following:

String.replace("Smith", "<a href='smithbio.html'>Smith</a>")
String.replace("Chairman Joe Smith", "<a href='smithbio.html'>Chairman Joe Smith</a>")

      

It would be bad, because Smith is used as part of his name anyway, and only Smith will be a reference.

But if I try the opposite:

String.replace("Chairman Joe Smith", "<a href='smithbio.html'>Chairman Joe Smith</a>")
String.replace("Smith", "<a href='smithbio.html'>Smith</a>")

      

This will create nested links.

I think maybe I should use regex.Replace in combination with substring checks? But if that's the case, I'm having trouble figuring out how to do it. How can I do these multiple replacements, but say that replace this string if it is not part of another string.replacer that is being called? FYI While doing this in VB, don't think it matters here, but just in case ...

+2


a source to share


3 answers


You should use regex like: (VB, tested)

Regex.Replace(str, "(Chairman\s+)?(Joe\s+)?Smith", _
    "<a href='smithbio.html'>$0</a>")

      



$0

is one of several expressions that can be included in the replacement string .

If you only know the names at runtime, you should call Regex.Escape .

+3


a source


One of the things you can do with .NET objects regex

is to replace the match with the result of the delegation passed to Regex.Replace

.



In a delegate, you can use the result of the match (and any string you want) when defining the text to replace (returned by the delegate).

+1


a source


I am not suggesting that you do this, however, it is imperative that programmers can infer and reason with algorithms from the problems they face, especially when maintaining legacy codebases. We are tainted by all high level abstractions. We just ask: how can I do X, Y, Z and an arrow, we throw a RegEx or LINQ query at it. I am not saying these are bad things, but every time it pays to think a little deeper. It might be more appropriate for Code Golf or something, but if the OP presented a reasoned algorithm I would feel much better about introducing the canned approach, because then the OP would probably admit himself that a regex can work like a solution.

Without using a regular expression, you can write and maintain a list of indices and lengths of the lines found:

  • Chairman Joe Smith
  • Joe Smith
  • Smith
  • Chairman Smith

You will then walk through that list, replacing each element with the appropriate link.

I'm sure this algorithm can be improved.

Here's an example:

class Instance
{
    public int start;
    public int length;
    public string text;
    public Instance(int _start, int _length, string _text)
    {
        start = _start;
        length = _length;
        text = _text;
    }
};

static void Main(string[] args)
{
    string test = "Chairman Joe Smith has announced a new plan to decrease expenditures by outsourcing the planning of the new dining hall. Smith states the current project managers do not have excess time to commit to this new project and this will be less costly than hiring a new or contract project manager.";
    string[] lookup = { "Chairman Joe Smith", "Joe Smith", "Smith", "Chairman Smith" };
    List<Instance> li = new List<Instance>();

    // record each instance of specified strings
    foreach (string name in lookup)
    {
        int index = 0;
        do
        {
            index = test.IndexOf(name, index);
            if (index > -1)
            {
                li.Add(new Instance(index, name.Length, name));
                index += name.Length;
            }
        } while (index > -1);
    }

    // eliminate duplicate instances
    Retry:
    foreach (Instance i in li)
    {
        foreach (Instance j in li)
        {
            if (j != i)
            {
                if ((j.start >= i.start) && (j.start + j.length <= i.start + i.length))
                {
                    li.Remove(j);
                    goto Retry;
                }
            }
        }
    }

    // replace each instance with respective text
    foreach (Instance i in li)
    {
        test = test.Remove(i.start, i.length);
        string final = "<a href='smithbio.html'>" + i.text + "</a>";
        test = test.Insert(i.start, final);
        foreach (Instance j in li)
        {
            j.start += (final.Length - i.length);
        }
    }

    Console.WriteLine(test);
    Console.ReadLine();
}

      

0


a source







All Articles