637 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			637 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
using System.Collections;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Text.RegularExpressions;
 | 
						|
using System.Text;
 | 
						|
using System;
 | 
						|
 | 
						|
using System.Globalization;
 | 
						|
using Godot;
 | 
						|
 | 
						|
namespace Rokojori
 | 
						|
{
 | 
						|
  public static class RegexUtility
 | 
						|
  {
 | 
						|
    public static Regex MakeSticky( Regex regex )
 | 
						|
    {
 | 
						|
      var source = MakeSourceSticky( regex + "" );
 | 
						|
 | 
						|
      return new Regex( source, regex.Options );
 | 
						|
    }
 | 
						|
 | 
						|
    public static string MakeSourceSticky( string source )
 | 
						|
    {
 | 
						|
      if ( ! source.StartsWith( "\\G" ) )
 | 
						|
      {
 | 
						|
        source = "\\G(?:" + source + ")";
 | 
						|
      }
 | 
						|
 | 
						|
      return source;
 | 
						|
    } 
 | 
						|
 | 
						|
    public static bool IsUpperCase( string value, int position )
 | 
						|
    {
 | 
						|
      if ( value == null || value.Length == 0 || value.Length <= position )
 | 
						|
      {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      var ch = ( value[ position ] + "" ).ToUpper();
 | 
						|
 | 
						|
      return ch == ( value[ position ] + "" );
 | 
						|
    }
 | 
						|
 | 
						|
    public static bool StartsWithUpperCase( string value )
 | 
						|
    {
 | 
						|
      return IsUpperCase( value, 0 );
 | 
						|
    }
 | 
						|
 | 
						|
    public static string NumberToString( double value )
 | 
						|
    {
 | 
						|
      try
 | 
						|
      {
 | 
						|
        var specifier = "G";
 | 
						|
 | 
						|
        return value.ToString( specifier, CultureInfo.InvariantCulture );
 | 
						|
      }
 | 
						|
      catch( System.Exception e )
 | 
						|
      {
 | 
						|
        RJLog.Log(e );
 | 
						|
      }
 | 
						|
 | 
						|
      return "0";
 | 
						|
    }
 | 
						|
 | 
						|
    public static string _F( this float value )
 | 
						|
    {
 | 
						|
      return value.ToString( "0.0", CultureInfo.InvariantCulture );
 | 
						|
    }
 | 
						|
 | 
						|
    public static string _FF( this float value )
 | 
						|
    {
 | 
						|
      return value.ToString( "0.00", CultureInfo.InvariantCulture );
 | 
						|
    }
 | 
						|
 | 
						|
    public static string _FFF( this float value )
 | 
						|
    {
 | 
						|
      return value.ToString( "0.000", CultureInfo.InvariantCulture );
 | 
						|
    }
 | 
						|
 | 
						|
    
 | 
						|
 | 
						|
    public static double ParseDouble( string source, double alternative = 0 )
 | 
						|
    {
 | 
						|
      try 
 | 
						|
      { 
 | 
						|
        double newValue = System.Double.Parse( source, CultureInfo.InvariantCulture );
 | 
						|
        return newValue;
 | 
						|
      }
 | 
						|
      catch ( System.Exception e )
 | 
						|
      {
 | 
						|
        if ( e != null )
 | 
						|
        {
 | 
						|
 | 
						|
        }
 | 
						|
        return alternative;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    public static float ParseFloat( string source, float alternative = 0 )
 | 
						|
    {
 | 
						|
      return ( float ) ParseDouble( source, alternative );
 | 
						|
    }
 | 
						|
 | 
						|
    public static int ParseInt( string source, int alternative = 0 )
 | 
						|
    {
 | 
						|
      var multiply = 1;
 | 
						|
      var value = 0;
 | 
						|
 | 
						|
      for ( int i = source.Length - 1; i >= 0 ; i-- )
 | 
						|
      {
 | 
						|
        var symbol = source[ i ];
 | 
						|
        
 | 
						|
        if ( i == 0  )
 | 
						|
        {
 | 
						|
          if ( symbol == '-' )
 | 
						|
          { 
 | 
						|
            return - value; 
 | 
						|
          }
 | 
						|
 | 
						|
          if ( symbol == '+' )
 | 
						|
          { 
 | 
						|
            return value; 
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        var digitValue = ParseDigit( symbol );
 | 
						|
        
 | 
						|
        if ( digitValue == -1 )
 | 
						|
        {
 | 
						|
          return alternative;
 | 
						|
        }
 | 
						|
 | 
						|
        value += digitValue * multiply;
 | 
						|
 | 
						|
        multiply *= 10;
 | 
						|
      }  
 | 
						|
 | 
						|
      return value;
 | 
						|
    }
 | 
						|
 | 
						|
    public static int ParseDigit( char c )
 | 
						|
    {
 | 
						|
      switch ( c )
 | 
						|
      {
 | 
						|
        case '0': return 0;
 | 
						|
        case '1': return 1;
 | 
						|
        case '2': return 2;
 | 
						|
        case '3': return 3;
 | 
						|
        case '4': return 4;
 | 
						|
        case '5': return 5;
 | 
						|
        case '6': return 6;
 | 
						|
        case '7': return 7;
 | 
						|
        case '8': return 8;
 | 
						|
        case '9': return 9;
 | 
						|
      }
 | 
						|
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    public static bool Matching( string source, string regex, RegexOptions options = RegexOptions.None )
 | 
						|
    {
 | 
						|
      if ( source == null )
 | 
						|
      {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      return new Regex( regex, options ).Match( source ).Success;
 | 
						|
    }
 | 
						|
 | 
						|
    public static bool MatchingIgnoreCase( string source, string regex )
 | 
						|
    {
 | 
						|
      return Matching( source, regex, RegexOptions.IgnoreCase );
 | 
						|
    }
 | 
						|
 | 
						|
    public static string Substring( string source, string regex )
 | 
						|
    {
 | 
						|
      return new Regex( regex ).Match( source ).Value;
 | 
						|
    }
 | 
						|
 | 
						|
    public static string EscapeForRegex( string source )
 | 
						|
    {
 | 
						|
      var sb = new StringBuilder();
 | 
						|
 | 
						|
      var escapes = "+*?^$\\.[]{}()|/";
 | 
						|
 | 
						|
      for ( int i = 0; i < source.Length; i++ )
 | 
						|
      {
 | 
						|
        var character = source[ i ];
 | 
						|
 | 
						|
        if ( escapes.IndexOf( character ) != -1 )
 | 
						|
        {
 | 
						|
          sb.Append( "\\" );
 | 
						|
        } 
 | 
						|
 | 
						|
        sb.Append( character );
 | 
						|
      }
 | 
						|
 | 
						|
      return sb.ToString();
 | 
						|
    }
 | 
						|
 | 
						|
    public static string LeadingZeros( int value, int minDigits = 2)
 | 
						|
    {
 | 
						|
      var stringValue = value + "";
 | 
						|
 | 
						|
      while ( stringValue.Length < minDigits )
 | 
						|
      {
 | 
						|
        stringValue = "0" + stringValue;
 | 
						|
      }
 | 
						|
 | 
						|
      return stringValue;
 | 
						|
    }
 | 
						|
 | 
						|
    public static string NumberWithThousandsSeperator( int value, string seperator = "." )
 | 
						|
    {
 | 
						|
      var isNegative = value < 0;
 | 
						|
 | 
						|
      if ( isNegative ){ value = - value; }
 | 
						|
 | 
						|
      var stringValue = value + "";
 | 
						|
 | 
						|
      var builder = new StringBuilder();
 | 
						|
 | 
						|
      for ( int i = 0; i < stringValue.Length; i++ )
 | 
						|
      {
 | 
						|
        var index = ( stringValue.Length - 1 ) - i ;
 | 
						|
 | 
						|
        if ( i % 4 == 3 )
 | 
						|
        {
 | 
						|
          builder.Append( seperator );
 | 
						|
        }
 | 
						|
 | 
						|
        builder.Append( stringValue[ index ] );
 | 
						|
      }
 | 
						|
 | 
						|
      var seperatorValue = builder.ToString();
 | 
						|
 | 
						|
      return Reverse( seperatorValue );
 | 
						|
    }
 | 
						|
 | 
						|
    public static string Reverse( string source )
 | 
						|
    {
 | 
						|
      char[] characters = source.ToCharArray();
 | 
						|
      System.Array.Reverse( characters );
 | 
						|
      return new string( characters );
 | 
						|
    }
 | 
						|
 | 
						|
    public static Regex EscapedOrRegex( string first, params string[] other )
 | 
						|
    {
 | 
						|
      var value = EscapeForRegex( first );
 | 
						|
      
 | 
						|
      for ( var i = 0; i < other.Length; i++ )
 | 
						|
      {
 | 
						|
        value += "|" + EscapeForRegex( other[ i ] );
 | 
						|
 | 
						|
        /*
 | 
						|
 | 
						|
        if ( i == 0 )
 | 
						|
        { 
 | 
						|
          value = "(" + value;
 | 
						|
        }         
 | 
						|
        value += ")|(" + EscapeForRegex( other[ i ] );
 | 
						|
 | 
						|
        if ( i == ( other.Length - 1 ) )
 | 
						|
        {
 | 
						|
          value += ")";
 | 
						|
        }
 | 
						|
 | 
						|
        */
 | 
						|
      }
 | 
						|
 | 
						|
      //Logs.Log("EscapedOrRegex:", "'" + value + "'");
 | 
						|
      return new Regex( value );
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    public static Color ParseColor( string source, Color alternative )
 | 
						|
    {
 | 
						|
      if ( Matching( source, @"#\d+" ) )
 | 
						|
      {
 | 
						|
        return ParseHexColor( source, alternative );
 | 
						|
      } 
 | 
						|
      else if ( Matching( source, @"^rgb" ) )
 | 
						|
      { 
 | 
						|
        return ParseRGBColor( source, alternative );
 | 
						|
      } 
 | 
						|
      else if ( Matching( source, @"^hsl" ) )
 | 
						|
      {
 | 
						|
        return ParseHSLColor( source, alternative );
 | 
						|
      }
 | 
						|
 | 
						|
      return alternative;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    public static double ParsePercentage( string source )
 | 
						|
    {
 | 
						|
      source = Remove( source, @"\s*%" );
 | 
						|
      return ParseDouble( source.Trim(), 0 ) / 100.0;
 | 
						|
    }
 | 
						|
 | 
						|
    public static int ParseHexCharacter( char hexCharacter )
 | 
						|
    {
 | 
						|
      if ( '0' <= hexCharacter && hexCharacter <= '9' )
 | 
						|
      {
 | 
						|
        return (int) (hexCharacter - '0' );
 | 
						|
      } 
 | 
						|
 | 
						|
      if ( 'a' <= hexCharacter && hexCharacter <= 'f' )
 | 
						|
      {
 | 
						|
        return (int) (hexCharacter - 'a') + 10;
 | 
						|
      }
 | 
						|
 | 
						|
      if ( 'A' <= hexCharacter && hexCharacter <= 'F' )
 | 
						|
      {
 | 
						|
        return (int) (hexCharacter - 'A') + 10;
 | 
						|
      }
 | 
						|
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static int ParseHex( string source )
 | 
						|
    {
 | 
						|
      var value = 0;
 | 
						|
      var shift = 0;
 | 
						|
 | 
						|
      for ( var i = source.Length - 1; i < source.Length; i++ )
 | 
						|
      {
 | 
						|
        var hexValue = ParseHexCharacter( source[ i ] ) << shift;
 | 
						|
        shift += 4;
 | 
						|
      }
 | 
						|
 | 
						|
      return value;
 | 
						|
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static Color ParseHexColor( string source, Color alternative )
 | 
						|
    {
 | 
						|
      source = RegexUtility.Remove( source, @"^#" ); 
 | 
						|
 | 
						|
      var numbers = new List<float>();
 | 
						|
 | 
						|
      for ( var i = 0; i < 3; i++ )
 | 
						|
      {
 | 
						|
        var value = source.Substring( i * 2, 2 );
 | 
						|
        var numberValue = ParseHex( value ) / 255f;
 | 
						|
        numbers.Add( numberValue );
 | 
						|
      }
 | 
						|
 | 
						|
      if ( numbers.Count == 3 )
 | 
						|
      {
 | 
						|
        numbers.Add( 1f );
 | 
						|
      } 
 | 
						|
 | 
						|
      return new Color( numbers[ 0 ], numbers[ 1 ], numbers[ 2 ] , numbers[ 3 ] );
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    public static Color ParseRGBColor( string source, Color alternative )
 | 
						|
    {
 | 
						|
      source = RegexUtility.Remove( source, @"^rgba?\(" ); 
 | 
						|
      source = RegexUtility.Remove( source, @"\)$" );
 | 
						|
      
 | 
						|
      var splits = Split( source, @"\," );
 | 
						|
      var numbers = Lists.Map<string,float>( splits, 
 | 
						|
        ( string value, int index ) =>
 | 
						|
        { 
 | 
						|
          if ( value.Contains( "%" ) )
 | 
						|
          {
 | 
						|
            return (float) ParsePercentage( value );
 | 
						|
          }
 | 
						|
           
 | 
						|
          return ParseFloat( value );
 | 
						|
        }
 | 
						|
      );
 | 
						|
 | 
						|
      if ( numbers.Count == 3 )
 | 
						|
      {
 | 
						|
        numbers.Add( 1f );
 | 
						|
      } 
 | 
						|
 | 
						|
      return new Color( numbers[ 0 ], numbers[ 1 ], numbers[ 2 ] , numbers[ 3 ] );
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    public static HSLColor ParseHSLColor( string source, HSLColor alternative )
 | 
						|
    {
 | 
						|
      source = RegexUtility.Remove( source, @"^hsl\(" ); 
 | 
						|
      source = RegexUtility.Remove( source, @"\)$" );
 | 
						|
      
 | 
						|
      var splits = Split( source, @"\," );
 | 
						|
      var numbers =Lists.Map<string,float>( splits, 
 | 
						|
        ( string value, int index ) =>
 | 
						|
        { 
 | 
						|
          if ( value.Contains( "%" ) )
 | 
						|
          {
 | 
						|
            return (float) ParsePercentage( value );
 | 
						|
          }
 | 
						|
           
 | 
						|
          return ParseFloat( value );
 | 
						|
        }
 | 
						|
      );
 | 
						|
 | 
						|
      if ( numbers.Count < 3 )
 | 
						|
      {
 | 
						|
        RJLog.Log("Not enough numbers parsed: ", source, ">>", numbers.Count, Lists.Join( numbers, "," ) );
 | 
						|
      }
 | 
						|
     
 | 
						|
 | 
						|
      if ( numbers.Count == 3 )
 | 
						|
      {
 | 
						|
        numbers.Add( 1f );
 | 
						|
      } 
 | 
						|
 | 
						|
      return new HSLColor( numbers[ 0 ], numbers[ 1 ], numbers[ 2 ] , numbers[ 3 ] );
 | 
						|
    }
 | 
						|
 | 
						|
    public static List<string> Split( string source, Regex regex )
 | 
						|
    { 
 | 
						|
      var strings = regex.Split( source );
 | 
						|
      var list = new List<string>();
 | 
						|
 | 
						|
      list.AddRange( strings );
 | 
						|
 | 
						|
      return list;
 | 
						|
    } 
 | 
						|
 | 
						|
    public static List<string> Split( string source, string regex )
 | 
						|
    {
 | 
						|
      return Split( source, new Regex( regex ) );
 | 
						|
    }
 | 
						|
 | 
						|
    public static List<string> SplitLines( string source )
 | 
						|
    {
 | 
						|
      var array = Regex.Split( source, "\r\n|\r|\n" );
 | 
						|
      var list = new List<string>();
 | 
						|
      list.AddRange( array );
 | 
						|
      return list;
 | 
						|
    }
 | 
						|
 | 
						|
    public static string Remove( string source, string regex )
 | 
						|
    {
 | 
						|
      return Replace( source, regex, "" );
 | 
						|
    }
 | 
						|
 | 
						|
    public static string Replace( string source, Regex regex, string replacement )
 | 
						|
    {
 | 
						|
      return regex.Replace( source, replacement );
 | 
						|
    }
 | 
						|
    
 | 
						|
    public static string Remove( string source, Regex regex )
 | 
						|
    {
 | 
						|
      return Replace( source, regex, "" );
 | 
						|
    }
 | 
						|
 | 
						|
    public static string Replace( string source, string regex, string replacement )
 | 
						|
    {
 | 
						|
      return new Regex( regex ).Replace( source, replacement );
 | 
						|
    }
 | 
						|
 | 
						|
    public static string ReplaceMultiple( string source, Dictionary<string,string> replacements )
 | 
						|
    {
 | 
						|
      var replaced = source;
 | 
						|
 | 
						|
      foreach ( var vk in replacements )
 | 
						|
      {
 | 
						|
        replaced = replaced.Replace( vk.Key, vk.Value );
 | 
						|
      }
 | 
						|
 | 
						|
      return replaced;
 | 
						|
    }
 | 
						|
 | 
						|
    public static string TrimToLastPathFragment( string path )
 | 
						|
    {
 | 
						|
      var splits = SplitPaths( path );
 | 
						|
 | 
						|
      return splits[ splits.Count - 1 ];
 | 
						|
    }
 | 
						|
 | 
						|
    public static bool StartsWithPathProtocol( string path )
 | 
						|
    {
 | 
						|
      return Matching( path, @"^\w+://" );
 | 
						|
    }
 | 
						|
 | 
						|
    public static string ExtractPathProtocol( string path )
 | 
						|
    {
 | 
						|
      if ( ! StartsWithPathProtocol( path) )
 | 
						|
      {
 | 
						|
        return "";
 | 
						|
      }
 | 
						|
 | 
						|
      var splitPosition = path.IndexOf( "://" );
 | 
						|
 | 
						|
      return path.Substring( 0, splitPosition + 3 ) ;
 | 
						|
    }
 | 
						|
 | 
						|
    public static string ParentPath( string path )
 | 
						|
    {
 | 
						|
      var protocol = ExtractPathProtocol( path );
 | 
						|
 | 
						|
      if ( protocol.Length != 0 )
 | 
						|
      {
 | 
						|
        path = path.Substring( protocol.Length );
 | 
						|
      }
 | 
						|
 | 
						|
      var list = SplitPaths( path );
 | 
						|
 | 
						|
      list.RemoveAt( list.Count -1 );
 | 
						|
 | 
						|
      return protocol + Lists.Join( list, "/" );
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    public static List<string> SplitPaths( string path )
 | 
						|
    {
 | 
						|
      var splittedPaths = new List<string>();
 | 
						|
      var normalizedPath = NormalizePath( path );
 | 
						|
      var splits = Split( normalizedPath, new Regex( @"\/" ) );
 | 
						|
      return splits;
 | 
						|
    } 
 | 
						|
 | 
						|
 | 
						|
    public static string ToValidCSName( string source)
 | 
						|
    {
 | 
						|
      var output = new StringBuilder();
 | 
						|
 | 
						|
      for ( int i = 0; i < source.Length; i++)
 | 
						|
      {
 | 
						|
        var s = source[ i ];
 | 
						|
        var isDigit  = Char.IsDigit( s );
 | 
						|
        var isLetter = Char.IsLetter( s );
 | 
						|
        var isAscii  = Char.IsAscii( s );
 | 
						|
 | 
						|
        var isDigitAsFirst = i == 0 && isDigit;
 | 
						|
        var isAllowed = ( isDigit || isLetter ) && isAscii;
 | 
						|
 | 
						|
        if ( isDigitAsFirst || ! isAllowed  )
 | 
						|
        {
 | 
						|
          output.Append( "_" );
 | 
						|
        } 
 | 
						|
        else
 | 
						|
        {
 | 
						|
          output.Append( source[ i ] );
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      source = output.ToString();
 | 
						|
 | 
						|
      return source.ToCamelCase();
 | 
						|
     
 | 
						|
    }   
 | 
						|
 | 
						|
    public static string JoinPaths( List<string> paths, int startIndex = 0, int length = -1 )
 | 
						|
    {
 | 
						|
      var normalizedPaths = new List<string>();
 | 
						|
      // normalizedPaths.AddRange( paths );
 | 
						|
 | 
						|
      var endIndex = startIndex + length;
 | 
						|
      var end = ( length < 0 || ( length + startIndex ) >= paths.Count ) ? paths.Count : endIndex;
 | 
						|
     
 | 
						|
      for ( var i = startIndex; i < end; i++ )
 | 
						|
      {
 | 
						|
        normalizedPaths.Add( _NormalizePath( paths[ i ] ) );
 | 
						|
      } 
 | 
						|
 | 
						|
      return Lists.Join( normalizedPaths, "/" ); 
 | 
						|
    }
 | 
						|
 | 
						|
    public static string Join( string pathA, string pathB, params string[] paths )
 | 
						|
    {
 | 
						|
      var normalizedPaths = new List<string>();
 | 
						|
      normalizedPaths.Add( pathA );
 | 
						|
      normalizedPaths.Add( pathB );
 | 
						|
      normalizedPaths.AddRange( paths );
 | 
						|
     
 | 
						|
      for ( var i = 0; i < normalizedPaths.Count; i++ )
 | 
						|
      {
 | 
						|
        normalizedPaths[ i ] = _NormalizePath( normalizedPaths[ i ] );
 | 
						|
      } 
 | 
						|
 | 
						|
      return Lists.Join( normalizedPaths, "/" );
 | 
						|
    }
 | 
						|
 | 
						|
    private static string _EnsureForwardSlashes( string path )
 | 
						|
    { 
 | 
						|
      if ( path.IndexOf( "\\" ) == -1 )
 | 
						|
      {
 | 
						|
        return path;
 | 
						|
      }  
 | 
						|
 | 
						|
      var correctedPath = "";
 | 
						|
      
 | 
						|
      for ( int i = 0; i < path.Length; i++ )
 | 
						|
      {
 | 
						|
        if ( path[ i ] == '\\' )
 | 
						|
        {
 | 
						|
          correctedPath += "/";
 | 
						|
        } 
 | 
						|
        else
 | 
						|
        {
 | 
						|
          correctedPath += path[ i ];
 | 
						|
        }         
 | 
						|
      }
 | 
						|
 | 
						|
      return correctedPath;
 | 
						|
    }
 | 
						|
 | 
						|
    public static string NormalizePath( string path )
 | 
						|
    {
 | 
						|
      return _NormalizePath( path );
 | 
						|
    }
 | 
						|
 | 
						|
    public static string WindowsPath( string path )
 | 
						|
    {
 | 
						|
      path = _NormalizePath( path );
 | 
						|
 | 
						|
      var slashes = @"\/";
 | 
						|
 | 
						|
      path = Regex.Replace( path, slashes, "\\" );
 | 
						|
 | 
						|
      return path;
 | 
						|
    }
 | 
						|
 | 
						|
    private static string _NormalizePath( string path )
 | 
						|
    {
 | 
						|
      path = _EnsureForwardSlashes( path );
 | 
						|
 | 
						|
      var startSlashes = @"^\/+";
 | 
						|
      var endSlashes = @"\/+$";
 | 
						|
      var multiples = @"\/\/+";
 | 
						|
 | 
						|
      path = Regex.Replace( path, startSlashes, "" );
 | 
						|
      path = Regex.Replace( path, endSlashes, "" );
 | 
						|
      path = Regex.Replace( path, multiples, "/" );
 | 
						|
 | 
						|
      return path;
 | 
						|
    }
 | 
						|
  }
 | 
						|
} |