В итоге я использовал регулярное выражение Unicode, которое частично реализовано в. NET. Используя этот вопрос (C# - Регулярное выражение для поиска суррогатной пары кодовой точки Unicode из любой строки? ), я придумал следующее.
Regex
//Returns the Emoji
@"([\uD800-\uDBFF][\uDC00-\uDFFF]\p{M}*){1,5}|\p{So}"
//Returns true if the string is a single Emoji
@"^(?>(?>[\uD800-\uDBFF][\uDC00-\uDFFF]\p{M}*){1,5}|\p{So})$"
Тесты
public class EmojiTests
{
private static readonly Regex IsEmoji = new Regex(@"^(?>(?>[\uD800-\uDBFF][\uDC00-\uDFFF]\p{M}*){1,5}|\p{So})$", RegexOptions.Compiled);
[Theory]
[InlineData("⭐")]
[InlineData("?")]
[InlineData("?")]
[InlineData("?")]
[InlineData("??")]
[InlineData("?")]//pinched fingers, coming soon :p
public void ValidEmojiCases(string input)
{
Assert.Matches(IsEmoji, input);
}
[Theory]
[InlineData("")]
[InlineData(":p")]
[InlineData("a")]
[InlineData("<")]
[InlineData("⭐⭐")]
[InlineData("?a")]
[InlineData("‼️")]
[InlineData("↔️")]
public void InvalidEmojiCases(string input)
{
Assert.DoesNotMatch(IsEmoji, input);
}
}
Это не идеально (т.е. возвращает истину для «™ ️», ложь для «◻️»), но этого достаточно.