2015-05-26 17 views
20

Ben :grinning:, :kissing_heart: veya :bouquet: gibi, ister ifade simgeleri için kod içeren bazı dizeleri var. Emoji kodlarını kaldırmak için onları işlemek isterim. Verilen örnek içinDize içeriğindeki bazı özel kelimeleri nasıl silebilirsiniz?

:

Merhaba: sırıtan: nasılsın:? kissing_heart: buket:

:

Bunu almak istiyorum ince misiniz

Merhaba, nasılsınız? İyi misin?

richTextBox2.Text = richTextBox1.Text.Replace(":kissing_heart:", "").Replace(":bouquet:", "").Replace(":grinning:", "").ToString(); 

Ancak, (bu yöntemi kullanarak, Replace() için 856 aramaları alacağını, hangi) kaldırmak zorunda 856 farklı emoji simgeleri vardır:

Ben bu kodu kullanabilirsiniz biliyorum. Bunu başarmanın başka bir yolu var mı?

+2

bir arama tablosu sorunu çözmek istiyorsunuz? –

+2

@demonplus: Bu sorgulama emoji char dizileri hakkında konuşurken, empji karakterlerini kaldırmaya ilişkin başvurulan bağlantı konuşmalarınız. Sadece String.Empty ile emoji değiştirmek istiyorsanız –

+1

, tüm emoj dizeleri içeren bir dizi tanımlamak ve sonra OP geniş dosyanın üzerine bu gidecektim Zihnimde String.Empty –

cevap

27

Sen :anything: arasındaki kelime maç için Regex kullanabilirsiniz. Replace'u kullanarak başka bir doğrulama yapabilirsiniz. Eğer bir lambda ifadesi faydalanmak Replace kullanmak istemiyorsanız

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:" 

, sadece kelimeleri bulma, @ yorye-Nathan belirtildiği gibi, \w kullanabilirsiniz.

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:" 
+2

'dan dizeleri bir içeriğini okumak' – SimpleVar

+2

bu yeterince güvenli olduğunu düşünüyor musunuz daha uygun olabilir? –

+2

Sonunda, kullanıcının kolonlar arasında herhangi bir şey yazmasına izin vermezsiniz. –

16
string Text = "Hello:grinning: , how are you?:kissing_heart: Are you fine?:bouquet:"; 

ı o

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

GÜNCELLEME bu şekilde çözecek - ayrıntı Yorum

diğer yaklaşım refering:

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)); 

Emojs

mevcut sadece yedek Ama değilim böyle kısa bir cha için bu büyük fark olup olmadığından emin değil t-dizeleri ve okunması/bakımı kolay olan kodların bulunması daha önemlidir. OP'nin sorusu, Text.Replace().Text.Replace() yedeklemesini azaltmak ve en verimli çözüm hakkında değildi.

+0

bunların yerine, bu muhtemelen içerir zaten tüm 856 emoij, bu yüzden ikinci yaklaşımınız daha yavaş olacaktır. Kısa bir çizgide kullanmayı planlıyorsa, performans artışı, okunabilirliği azaltabilmek için asla yeterli olmayabilir. (W \ *): yanlış – Dorus

+0

, ilk yazı Sayes _I bir messenger_ – fubo

7

Tüm 856 emoji öğelerini değiştirmek zorunda değilsiniz. Sadece dizede görünenleri değiştirmeniz gerekir. Eğer tüm belirteçleri arasında dizeleri yani ekstraktı Temelde

Finding a substring using C# with a twist

: Yani bir göz ve: ve sonra String.Empty() sahip olanların yerini arama dönecektir endişe varsa

emojis olmayan dizeler gibi: başka bir metin: o zaman bu belirtilen jetonu değiştirmenin uygun olduğundan emin olmak için bir karma tablo araması olabilir.

8

Zaten önerilen bazı teknikler bir arada kullanmak. İlk olarak, 800+ emoji dizgisini bir veritabanında depolarım ve daha sonra bunları çalışma zamanında yüklerim.Bunları hafızaya kaydetmek için bir HashSet kullanın, böylece bir O (1) arama süremiz (çok hızlı). ... tüm potansiyel desen girişten eşleşir ve sonra geçerli olanları kaldırarak ve kullanıcı kendilerini girmiştir olmayan herhangi emoji kalıplarını bırakarak bizim karma emoji'ye her karşılaştırmak sonuçlanır

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); 
    } 
} 

çekmeyi Regex kullanın :

Merhaba: imadethis :, nasılsın? İyi misin? Bu: a: tuhaf: şey: yazmak için: fakat geçerli: yine de:

+1

Bu çok etkili değil. output.Replace (...) 'dizesinin tamamını ikinci kez aramak zorunda kalacak. Kendini değiştirin, emoij'in tüm örneklerini zaten değiştirecektir, ancak eşleştiriciniz aynı emoij ile ikinci kez eşleşebilir ve bu da Replace'in ikinci kez gereksiz yere çalıştırılmasına neden olabilir. – Dorus

+0

Kesinlikle haklısınız, eşleşme listesini, aralarında döngü yapmadan önce farklı (benzersiz) dizelerden oluşan bir koleksiyona dönüştürdüm. – Detail

+0

İstisnai bir iş çıkardın. Cevabın ve @Dorus cevabı arasında seçim yapmakta gerçekten zor bir zaman geçirdim, ikiniz de lütfumu hakediyorsunuz. – adricadar

5

Sonunda bir şeyler yazıp, bir şeyler yazmayı denedik. Daha önce bahsettiğim fikirleri bir araya getiriyorum, aslında sadece bir kez dizgeyi aşmamız gerekiyor. Bu gereksinime göre, bu Linq için mükemmel bir iş gibi geliyor.

Muhtemelen HashSet önbelleğe gerekir. Bunun dışında, bu O (n) performansa sahip ve sadece bir kez liste üzerinde gider. Kıyaslama açısından ilginç olurdu, ancak bu en verimli çözüm olabilir.

yaklaşım oldukça düz ileri olduğunu.

  • İlk önce tüm Emoij'i bir HashSet numaralı telefona yükleyin, böylece hızlı bir şekilde onlara bakabiliriz.
  • Bölünmüş : de input.Split(':') ile dize.
  • Geçerli öğeyi koruduğumuza karar verin. sonuncu ayağı maç olsaydı
    • , cari elemanı tutun.
    • Son eleman eşleşmiyorsa, geçerli öğenin eşleşip eşleşmediğini kontrol edin.
      • Eğer varsa, bunu görmezden. (Bu, substring'i çıkıştan etkin bir şekilde kaldırır).
      • Yapmıyorsa, :'u geri takın ve saklayın.
  • bir StringBuilder ile dize yeniden oluşturun.
    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(); 
         } 
        } 
    } 
    

    Düzenleme

: Ben Rx library kullanarak serin bir şey yaptım, ama sonra Aggregate böylece daha da kod basitleştirilmesi, Rx Scan arasında IEnumerable karşılığıdır fark etti.

+0

Hızlı yapmaya çok konsantre oldunuz ve başarılısınız. – adricadar

+0

@adricadar Bu bir takıntısı oldu evet :-) – Dorus

3

verimliliği üzerinde durulduğu ve "yanlış pozitif" işleme önlemek özel emoji simgeleri atlarken bir StringBuilder kullanarak dizeyi yeniden düşünmeye edin:

static HashSet<string> emojis = new HashSet<string>() 
{ 
    "grinning", 
    "kissing_heart", 
    "bouquet" 
}; 

static string RemoveEmojis(string input) 
{ 
    StringBuilder sb = new StringBuilder(); 

    int length = input.Length; 
    int startIndex = 0; 
    int colonIndex = input.IndexOf(':'); 

    while (colonIndex >= 0 && startIndex < length) 
    { 
     //Keep normal text 
     int substringLength = colonIndex - startIndex; 
     if (substringLength > 0) 
      sb.Append(input.Substring(startIndex, substringLength)); 

     //Advance the feed and get the next colon 
     startIndex = colonIndex + 1; 
     colonIndex = input.IndexOf(':', startIndex); 

     if (colonIndex < 0) //No more colons, so no more emojis 
     { 
      //Don't forget that first colon we found 
      sb.Append(':'); 
      //Add the rest of the text 
      sb.Append(input.Substring(startIndex)); 
      break; 
     } 
     else //Possible emoji, let's check 
     { 
      string token = input.Substring(startIndex, colonIndex - startIndex); 

      if (emojis.Contains(token)) //It's a match, so we skip this text 
      { 
       //Advance the feed 
       startIndex = colonIndex + 1; 
       colonIndex = input.IndexOf(':', startIndex); 
      } 
      else //No match, so we keep the normal text 
      { 
       //Don't forget the colon 
       sb.Append(':'); 

       //Instead of doing another substring next loop, let's just use the one we already have 
       sb.Append(token); 
       startIndex = colonIndex; 
      } 
     } 
    } 

    return sb.ToString(); 
} 

static void Main(string[] args) 
{ 
    List<string> inputs = new List<string>() 
    { 
     "Hello:grinning: , how are you?:kissing_heart: Are you fine?:bouquet:", 
     "Tricky test:123:grinning:", 
     "Hello:grinning: :imadethis:, how are you?:kissing_heart: Are you fine?:bouquet: This is:a:strange:thing :to type:, but valid :nonetheless:" 
    }; 

    foreach (string input in inputs) 
    { 
     Console.WriteLine("In <- " + input); 
     Console.WriteLine("Out -> " + RemoveEmojis(input)); 
     Console.WriteLine(); 
    } 

    Console.WriteLine("\r\n\r\nPress enter to exit..."); 
    Console.ReadLine(); 
} 

Çıkışlar:

In <- Hello:grinning: , how are you?:kissing_heart: Are you fine?:bouquet: 
Out -> Hello , how are you? Are you fine? 

In <- Tricky test:123:grinning: 
Out -> Tricky test:123 

In <- Hello:grinning: :imadethis:, how are you?:kissing_heart: Are you fine?:bouquet: This is:a:strange:thing :to type:, but valid :nonetheless: 
Out -> Hello :imadethis:, how are you? Are you fine? This is:a:strange:thing :to type:, but valid :nonetheless: 
3

bunu kullanın Ben koydum kodu bu işlevi kullanarak düşünüyorum senin sorunun çözülecek.

public static class Helper 
{ 
    public static string MyReplace(this string dirty, char separator) 
    { 
     string newText = ""; 
     bool replace = false; 

     for (int i = 0; i < dirty.Length; i++) 
     { 
      if(dirty[i] == separator) { replace = !replace ; continue;} 
      if(replace) continue; 
      newText += dirty[i]; 
     } 
     return newText; 
    } 

}

Kullanım:

 string s = "Hello:grinning: , how are you?:kissing_heart: Are you fine?:bouquet:"; 

     string rmv = ""; string remove = ""; 
     int i = 0; int k = 0; 
    A: 
     rmv = ""; 
     for (i = k; i < s.Length; i++) 
     { 
      if (Convert.ToString(s[i]) == ":") 
      { 
       for (int j = i + 1; j < s.Length; j++) 
       { 
        if (Convert.ToString(s[j]) != ":") 
        { 
         rmv += s[j]; 
        } 
        else 
        { 
         remove += rmv + ","; 
         i = j; 
         k = j + 1; 
         goto A; 
        } 
       } 
      } 
     } 

     string[] str = remove.Split(','); 
     for (int x = 0; x < str.Length-1; x++) 
     { 
      s = s.Replace(Convert.ToString(":" + str[x] + ":"), ""); 
     } 
     Console.WriteLine(s); 
     Console.ReadKey(); 
3

böyle uzatma yöntemi kullanmak olur

richTextBox2.Text = richTextBox2.Text.MyReplace (':'); ':' Ardından bulundu emoji isimlerin hariç dize inşa

Bu yöntem göstermek Birlikte metni bölmek Regex

+0

Gerçekten, bazı ms 'ms' kaydetmek ama ': her şey:' arasında her şeyi kaldırır. – adricadar

+0

Doğru, ama tam olarak ne yapması gerektiği; Regex.Replace öğesini, ':' ile başlayan ve biten tüm metinlerle eşleşen bir desen kullanırsanız, sonuç aynı olur; Ancak Regex zaman zaman çok yavaş ... (özellikle de nasıl kullanacağını bilmiyorsanız) – Fabjan

0

ile kıyaslanamaz performans açısından daha iyi olacaktır.

 const char marker = ':'; 
     var textSections = text.Split(marker); 

     var emojiRemovedText = string.Empty; 

     var notMatchedCount = 0; 
     textSections.ToList().ForEach(section => 
     { 
      if (emojiNames.Contains(section)) 
      { 
       notMatchedCount = 0; 
      } 
      else 
      { 
       if (notMatchedCount++ > 0) 
       { 
        emojiRemovedText += marker.ToString(); 

       } 
       emojiRemovedText += section; 
      } 
     }); 
İlgili konular