如何从字符串内容中删除一些特殊单词?

JAC*_*JAC 20 c# string-formatting

我有一个包含了表情符号图标,如代码一些字符串:grinning:,:kissing_heart::bouquet:.我想处理它们以删除表情符号代码.

例如,给定:

你好:咧嘴笑:你好吗?:kissing_heart:你还好吗?:花束:

我想得到这个:

你好,你好吗?你还好吗?

我知道我可以使用这段代码:

richTextBox2.Text = richTextBox1.Text.Replace(":kissing_heart:", "").Replace(":bouquet:", "").Replace(":grinning:", "").ToString();
Run Code Online (Sandbox Code Playgroud)

但是,我必须删除856个不同的表情符号图标(使用此方法,将需要856个调用Replace()).有没有其他方法可以实现这一目标?

adr*_*dar 27

您可以使用Regex匹配两者之间的单词:anything:.使用Replacewith功能可以进行其他验证.

string pattern = @":(.*?):";
string input = "Hello:grinning: , how are you?:kissing_heart: Are you fine?:bouquet: Are you super fan, for example. :words not to replace:";
string output = Regex.Replace(input, pattern, (m) =>
{
    if (m.ToString().Split(' ').Count() > 1) // more than 1 word and other validations that will help preventing parsing the user text
    {
        return m.ToString();
    }
    return String.Empty;
}); // "Hello , how are you? Are you fine? Are you super fan, for example. :words not to replace:"
Run Code Online (Sandbox Code Playgroud)

如果您不想使用Replacelambda表达式,可以使用\w@ yorye-nathan提到的仅匹配单词.

string pattern = @":(\w*):";
string input = "Hello:grinning: , how are you?:kissing_heart: Are you fine?:bouquet: Are you super fan, for example. :words not to replace:";
string output = Regex.Replace(input, pattern, String.Empty); // "Hello , how are you? Are you fine? Are you super fan, for example. :words not to replace:"
Run Code Online (Sandbox Code Playgroud)

  • `:(\w*):`可能更合适 (2认同)
  • 你认为这足够安全吗? (2认同)
  • 你最终不允许用户在冒号之间写任何东西. (2认同)
  • 这怎么处理'棘手的测试:123:咧嘴笑:`?(应该成为`Tricky test:123`,因为`123`不是表情符号.) (2认同)
  • 几天来一直在思考这个问题,它可能比使用已经建议的"HashSet"要好得多.fubo已经提出的建议稍微容易一些.此外,您可以通过为表情符号添加最小和最大长度来使您的正则表达式更简单.如在`:(\w {4,15})中:`(其中4和15应该是最短和最长的表情符号代码的长度.) (2认同)

fub*_*ubo 16

string Text = "Hello:grinning: , how are you?:kissing_heart: Are you fine?:bouquet:";
Run Code Online (Sandbox Code Playgroud)

我会这样解决的

List<string> Emoj = new List<string>() { ":kissing_heart:", ":bouquet:", ":grinning:" };
Emoj.ForEach(x => Text = Text.Replace(x, string.Empty));
Run Code Online (Sandbox Code Playgroud)

更新 - 参考详细信息的评论

另一种方法:只替换现有的Emojs

List<string> Emoj = new List<string>() { ":kissing_heart:", ":bouquet:", ":grinning:" };
var Matches = Regex.Matches(Text, @":(\w*):").Cast<Match>().Select(x => x.Value);
Emoj.Intersect(Matches).ToList().ForEach(x => Text = Text.Replace(x, string.Empty));
Run Code Online (Sandbox Code Playgroud)

但我不确定这种短聊天字符串是否存在巨大差异,而且拥有易于阅读/维护的代码更为重要.OP的问题是减少冗余Text.Replace().Text.Replace()而不是最有效的解决方案.


Det*_*ail 8

我会结合使用已经建议的一些技术.首先,我将800多个表情符号字符串存储在数据库中,然后在运行时加载它们.使用HashSet将它们存储在内存中,这样我们就有了O(1)查找时间(非常快).使用正则表达式从输入中提取所有可能的模式匹配,然后将每个模式匹配与我们的哈希表情符号进行比较,删除有效的表情符号并保留用户自己输入的任何非表情符号模式...

public class Program
{
    //hashset for in memory representation of emoji,
    //lookups are O(1), so very fast
    private HashSet<string> _emoji = null;

    public Program(IEnumerable<string> emojiFromDb)
    {
        //load emoji from datastore (db/file,etc)
        //into memory at startup
        _emoji = new HashSet<string>(emojiFromDb);
    }

    public string RemoveEmoji(string input)
    {
        //pattern to search for
        string pattern = @":(\w*):";
        string output = input;

        //use regex to find all potential patterns in the input
        MatchCollection matches = Regex.Matches(input, pattern);

        //only do this if we actually find the 
        //pattern in the input string...
        if (matches.Count > 0)
        {
            //refine this to a distinct list of unique patterns 
            IEnumerable<string> distinct = 
                matches.Cast<Match>().Select(m => m.Value).Distinct();

            //then check each one against the hashset, only removing
            //registered emoji. This allows non-emoji versions 
            //of the pattern to survive...
            foreach (string match in distinct)
                if (_emoji.Contains(match))
                    output = output.Replace(match, string.Empty);
        }

        return output;
    }
}

public class MainClass
{
    static void Main(string[] args)
    {
        var program = new Program(new string[] { ":grinning:", ":kissing_heart:", ":bouquet:" });
        string output = program.RemoveEmoji("Hello:grinning: :imadethis:, how are you?:kissing_heart: Are you fine?:bouquet: This is:a:strange:thing :to type:, but valid :nonetheless:");
        Console.WriteLine(output);
    }
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

你好:imadethis:你好吗?你还好吗?这是:a:奇怪的:东西:输入:,但有效:尽管如此:


The*_*dge 7

您不必更换所有856表情符号.您只需要替换字符串中出现的那些.所以看看:

使用带有扭曲的C#查找子字符串

基本上你提取所有标记,即:和:之间的字符串,然后用string.Empty()替换它们

如果您担心搜索将返回非emojis的字符串,例如:其他一些文本:那么您可以进行哈希表查找以确保替换所述找到的令牌是合适的.


Dor*_*rus 5

终于到处写了一些东西.我正在结合前面提到的几个想法,事实上我们应该只循环一次字符串.基于这些要求,这听起来像是完美的工作Linq.

你可能应该缓存HashSet.除此之外,这具有O(n)性能,并且仅在列表上进行一次.对基准测试很有意思,但这很可能是最有效的解决方案.

这种方法非常简单.

  • 首先加载所有Emoij,HashSet以便我们快速查找它们.
  • input.Split(':')the 分割字符串:.
  • 决定我们是否保留当前元素.
    • 如果最后一个元素匹配,则保留当前元素.
    • 如果最后一个元素不匹配,请检查当前元素是否匹配.
      • 如果是,请忽略它.(这有效地从输出中删除了子串).
      • 如果没有,请追加:并保留.
  • 用a重建我们的字符串StringBuilder.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    static class Program
    {
        static void Main(string[] args)
        {
            ISet<string> emojiList = new HashSet<string>(new[] { "kissing_heart", "bouquet", "grinning" });

            Console.WriteLine("Hello:grinning: , ho:w: a::re you?:kissing_heart:kissing_heart: Are you fine?:bouquet:".RemoveEmoji(':', emojiList));
            Console.ReadLine();
        }

        public static string RemoveEmoji(this string input, char delimiter, ISet<string> emojiList)
        {
            StringBuilder sb = new StringBuilder();
            input.Split(delimiter).Aggregate(true, (prev, curr) =>
            {
                if (prev)
                {
                    sb.Append(curr);
                    return false;
                }
                if (emojiList.Contains(curr))
                {
                    return true;
                }
                sb.Append(delimiter);
                sb.Append(curr);
                return false;
            });
            return sb.ToString();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:我使用Rx库做了一些很酷的事情,但后来实现了RxAggregate中的IEnumerable对应物Scan,从而进一步简化了代码.