воскресенье, 2 июня 2013 г.

Как сравнить строки с "*" и "?"

Зачастую встает задача сравнить две строки с использованием так называемых "wildcard" - спецсимволов "*" (произвольное количество любых символов) и "?" (один любой символ). Конечно, есть регулярные выражения. Но что если маску должен задавать пользователь, а в сложных выражениях просто нет необходимости. На этот случай я сделал себе маленький класс-помощник. Выкладываю тут - вдруг, еще кому пригодится.
public static class StringHelper
{
   static bool CompareWithPart( string source, string part )
   {
      if( source.Length != part.Length )
         return false;
      for( int i = 0; i < source.Length; i++ )
         if( source[i] != part[i] && part[i] != '?' )
            return false;
      return true;
   }

   static bool ConsumePart( ref string source, string part, bool first, bool last )
   {
      if( part == string.Empty )
      {
         if( last ) source = "";
         return !(first && last);
      }
      if( last )
      {
         var subStr = first ? source : source.Substring( Math.Max( 0, source.Length - part.Length ) );
         source = "";
         return CompareWithPart( subStr, part );
      }
      if( first )
      {
         var len = Math.Min( part.Length, source.Length );
         var subStr = source.Substring( 0, len );
         source = source.Substring( len );
         return CompareWithPart( subStr, part );
      }
      for( int i = 0; i <= source.Length - part.Length; i++ )
         if( CompareWithPart( source.Substring( i, part.Length ), part ) )
         {
            source = source.Substring( i + part.Length );
            return true;
         }
      return false;
   }

   public static bool CompareWildcard( this string source, string mask )
   {
      if( source == null )
         throw new ArgumentNullException( "source" );
      if( mask == null )
         throw new ArgumentNullException( "mask" );
      var parts = mask.Split( '*' );
      for( int i = 0; i < parts.Length; i++ )
         if( !ConsumePart( ref source, parts[i], i == 0, i == parts.Length - 1 ) )
            return false;
      return true;
   }

   public static bool CompareWildcard( this string source, string mask, bool ignoreCase )
   {
      if( source == null )
         throw new ArgumentNullException( "source" );
      if( mask == null )
         throw new ArgumentNullException( "mask" );
      return ignoreCase
         ? source.ToLower().CompareWildcard( mask.ToLower() )
         : source.CompareWildcard( mask );
   }

}
Использовать этот класс очень просто. Например так:
Console.WriteLine( "Мама моет раму".CompareWildcard( "*раму" ) );
Console.WriteLine( "Мама моет раму".CompareWildcard( "Мама*" ) );
Console.WriteLine( "Мама моет раму".CompareWildcard( "*моет*" ) );
Есть вопросы? Пишите в комментарии.

Комментариев нет:

Отправить комментарий