Home > OS >  Remove multiple "words" from a string by predefined indexes in C#?
Remove multiple "words" from a string by predefined indexes in C#?

Time:10-25

I'm trying to create my first chat bot for Twitch and I've ran into some issues with the emotes Twitch uses.

I need to be able to delete several emotes (emotes on Twitch are just words) from a string.
I don't know what the word is, but I know where in the string the word is located at, the starting index and length that is.

For example, the message: Hello HeyGuys how are you? WutFace WutFace produces the following on Twitch:

enter image description here

Using tmi.js I can fetch this message, including the emotes in the message and send them to my C# program.
The message I receive in C# from tmi.js looks like this:

{ '28087': [ '27-33', '35-41' ], '30259': [ '6-12' ] }

Where "28087" and "30259" are the IDs of the emotes and 27-33, 35-41 and 6-12 are the position of the emotes within the message itself.

How can I delete all those words/emotes from my string with the predefined start and stop positions of each word/emote?

A non successful attempt by me:

dynamic json = JsonConvert.DeserializeObject(emotes); // { '28087': [ '27-33', '35-41' ], '30259': [ '6-12' ] }
int prevLength = 0;
foreach (var a in json)
{
    foreach (var b in a)
    {
        for (int i = 0; i < b.Count; i  )
        {
            string range = b[i];
            int start = Convert.ToInt32(range.Split('-')[0]);
            int end = Convert.ToInt32(range.Split('-')[1]);
            int length = end - start;
            length = length   1;
            if (prevLength != 0)
            {
                start = start - prevLength;
            }
            prevLength = prevLength   length;
            message = message.Remove(start, length);
        }
    }
}

The above code can delete multiple emotes/words from the string as long as the emote/word is the same. Mixing emotes/words does not work.

CodePudding user response:

First of all, I'd encourage you to get rid of that dynamic. Not only because you completely lose type safety, but also because it makes it harder to understand what you're doing. You can have a much nicer structure with just:

var ranges = JsonConvert
    .DeserializeObject<Dictionary<string, string[]>>(emotes)
    // Get the strings in each list, the Key doesn't matter here
    .SelectMany(x => x.Value)
    // And transform the strings into objects like { int Start; int End; }
    .Select(x => 
    { 
        var splitted = x.Split('-'); 

        return new 
        { 
            Start = int.Parse(splitted[0]), 
            End = int.Parse(splitted[1]) 
        }; 
    });

Now, you don't need 3 loops, you don't need to worry about splitting, parsing nor anything else. You just need to work on removing those indexes from your string:

foreach (var range in ranges)
{
    // TODO: remove range from message using range.Start and range.End
}

Already much simpler! Now, as for actually removing the emotes, you need to carefully consider the indexes of the rest of the emotes once you remove one.
You could take each random emote and deal with the start and end index in message after each removal, but that's error prone and overall just too complex.
There's a much simpler way to do this, and it's by starting from the last emote and working your way up to the first, and achieving this is only:

var ranges = JsonConvert
    // ... existing code
    .OrderByDescending(x => x.End);

So now you have all the ranges ordered by their end position, allowing you to get rid of them quite easily:

foreach (var range in ranges)
{
    message = message.Remove(range.Start, range.End - range.Start   1);
}

Take a look at this in action: https://dotnetfiddle.net/QkktG3

Hello HeyGuys how are you? WutFace WutFace
Hello HeyGuys how are you? WutFace 
Hello HeyGuys how are you?  
Hello  how are you?
  •  Tags:  
  • c#
  • Related