Parser un long sur une base de 36

Parser un long sur une base de 36 - C#/.NET managed - Programmation

Marsh Posté le 29-07-2008 à 17:03:32    

Bonjour,
 
J'ai un petit souci dans la refonte d'une petite appli J2SE en C#. Le programme utilise la fonction :
 

Code :
  1. Long.parseLong(new String(tmp), 36)


 
tmp etant un tableau de byte (byte[])
 
Apparament le 36 est la base sur lequel il faut s'appuyer.  
 
Etant donnée qu'il ne sagit pas d'une base courante, je ne sais pas comment faire de même en C#.
 
Si qqn à la solution, merci.

Reply

Marsh Posté le 29-07-2008 à 17:03:32   

Reply

Marsh Posté le 30-07-2008 à 12:56:17    

c'est à dire ? chaque byte de ton tmp va de 0 à 35, c'est ça ?
 
et si t'as par exemple :
 
24 14
 
tu veux avoir 24*36 + 14 = 878 ?
 
ils sont triés dans quel ordre tes bytes dans tmp ?
 
genre c'est un byte[n] et les valeurs sont remplies par la fin en remontant vers 0, l'index n-1 étant l'unité ?
ou si c'est l'inverse ? (index 0 = unité, index 1 = dizaine, etc.)
 
dans tous les cas, pour moi t'es bon pour faire une méthode à la main qui gère le truc, parceque tu bosses pas à proprement en base 36 (base 36 ce sera plutôt une représentation string au format 0-9a-z à mon avis)
 
ou alors ton tmp contient les valeurs ASCII des caractères 0-9a-z ? (et dans ce cas, effectivement tu bosses bien en base 36 au niveau de ton string), mais rien que le string(byte[]) ça ne marchera pas. en C#, byte et char ne sont pas synonymes et n'ont rien à voir.
 
à priori, va falloir faire un truc à la mano.


Message édité par MagicBuzz le 30-07-2008 à 13:00:33
Reply

Marsh Posté le 30-07-2008 à 13:35:20    

creusois a écrit :

Bonjour,

 

J'ai un petit souci dans la refonte d'une petite appli J2SE en C#. Le programme utilise la fonction :

 
Code :
  1. Long.parseLong(new String(tmp), 36)
 

tmp etant un tableau de byte (byte[])

 

Apparament le 36 est la base sur lequel il faut s'appuyer.

 

Etant donnée qu'il ne sagit pas d'une base courante, je ne sais pas comment faire de même en C#.

 

Si qqn à la solution, merci.


Tu as Convert.ToInt32(String, IFormatProvider) et Convert.ToString(Int32, IFormatProvider), mais MS n'a apparement jugé bon ni de supporter des bases arbitraire (Convert.ToInt32(String, Int32) et Convert.ToString(Int32, Int32) ne gèrent que les bases 2, 8, 10, et 16) ni d'inclure un IFormatProvider permettant de récupérer un format pour une base arbitraire (pour autant que je puisse le voir en tout cas).

 

Essaies de chercher sur google si tu en trouves un fait par quelqu'un d'autre.


Message édité par masklinn le 30-07-2008 à 13:35:50

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 30-07-2008 à 14:03:50    

Je viens de coder ça, ça m'a l'air de marcher...
 

Code :
  1. using System;
  2. using SandBoxConsole.Base36;
  3. namespace SandBoxConsole
  4. {
  5.    class Program
  6.    {
  7.        static void Main(string[] args)
  8.        {
  9.            string s = "1a";
  10.            Console.WriteLine(s);
  11.            Number n = (Number)s;
  12.            Console.WriteLine((long)n);
  13.            Console.WriteLine((string)n);
  14.            long l = (long)n;
  15.            Console.WriteLine(l);
  16.            Console.WriteLine((string)((Number)l));
  17.            Console.ReadKey(true);
  18.        }
  19.    }
  20.    namespace Base36
  21.    {
  22.        class Digit
  23.        {
  24.            public const string EnumDigits = "0123456789abcdefghijklmnopqrstuvwxyz";
  25.            private char digit;
  26.            public Digit(int d)
  27.            {
  28.                char tmp;
  29.                if (char.TryParse(char.ConvertFromUtf32(d).ToLower(), out tmp))
  30.                {
  31.                    if (tmp >= '0' && tmp <= '9' || tmp >= 'a' && tmp <= 'z')
  32.                    {
  33.                        digit = tmp;
  34.                        return;
  35.                    }
  36.                }
  37.                throw new OverflowException(string.Format("Le code UTF32 '{0}' n'est pas un caractère reconnu en base 36.", d));  
  38.            }
  39.            public Digit(char d)
  40.            {
  41.                d = char.ToLower(d);
  42.                if (d >= '0' && d <= '9' || d >= 'a' && d <= 'z')
  43.                {
  44.                    digit = d;
  45.                    return;
  46.                }
  47.                throw new OverflowException(string.Format("Le caractère '{0}' n'est pas un caractère reconnu en base 36.", d));  
  48.            }
  49.            public char ToChar()
  50.            {
  51.                return digit;
  52.            }
  53.            public long ToLong()
  54.            {
  55.                return EnumDigits.IndexOf(digit);
  56.            }
  57.            public static explicit operator char(Digit value)
  58.            {
  59.                return value.ToChar();
  60.            }
  61.            public static explicit operator long(Digit value)
  62.            {
  63.                return value.ToLong();
  64.            }
  65.            public static explicit operator Digit(char value)
  66.            {
  67.                return new Digit(value);
  68.            }
  69.            public static explicit operator Digit(int value)
  70.            {
  71.                return new Digit(value);
  72.            }
  73.        }
  74.        class Number
  75.        {
  76.            private Digit[] digits;
  77.            public Number(long n)
  78.            {
  79.                
  80.                digits = new Digit[(int)Math.Ceiling(Math.Log(n, 36))];
  81.                int i = 0;
  82.                while (n > 0)
  83.                {
  84.                    digits[i++] = (Digit)Digit.EnumDigits[(int)(n % 36)];
  85.                    n /= 36;
  86.                }
  87.            }
  88.            public Number(string s)
  89.            {
  90.                digits = new Digit[s.Length];
  91.                for (int i = 0, cpt = s.Length - 1; i <= cpt; i++)
  92.                {
  93.                    digits[i] = new Digit(s[cpt - i]);
  94.                }
  95.            }
  96.            public long ToLong()
  97.            {
  98.                long n = 0;
  99.                long mul = 1;
  100.                for (int i = 0, cpt = digits.Length; i < cpt; i++)
  101.                {
  102.                    n += (long)digits[i] * mul;
  103.                    mul *= 36;
  104.                }
  105.                return n;
  106.            }
  107.            public override string ToString()
  108.            {
  109.                string s = string.Empty;
  110.                for (int i = digits.Length - 1; i >= 0; i--)
  111.                {
  112.                    s += (char)digits[i];
  113.                }
  114.                return s;
  115.            }
  116.            public static explicit operator Number(long value)
  117.            {
  118.                return new Number(value);
  119.            }
  120.            public static explicit operator Number(string value)
  121.            {
  122.                return new Number(value);
  123.            }
  124.            public static explicit operator long(Number value)
  125.            {
  126.                return value.ToLong();
  127.            }
  128.            public static explicit operator string(Number value)
  129.            {
  130.                return value.ToString();
  131.            }
  132.        }
  133.    }
  134. }


 


1a
46
1a
46
1a


Message édité par MagicBuzz le 30-07-2008 à 14:11:47
Reply

Marsh Posté le 30-07-2008 à 14:07:29    

(sauf qu'en fait, ça calcule pas bien, je vérifie j'ai une couille quelque part :D)

Reply

Marsh Posté le 30-07-2008 à 14:10:24    

[:prozac]  
 
http://www.codeproject.com/KB/reci [...] erter.aspx


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 30-07-2008 à 14:11:54    

Voilà, c'est corrigé ;)

Reply

Marsh Posté le 30-07-2008 à 14:13:07    

Ouais ben mon truc il marche bien et c'est pas du repompage d'un site :o
 
Et à l'utilisation, tu gardes ta valeur dans ta base, tu passes pas par des strings à tout bout de champ :spamafote:

Message cité 1 fois
Message édité par MagicBuzz le 30-07-2008 à 14:14:13
Reply

Marsh Posté le 30-07-2008 à 14:19:46    

MagicBuzz a écrit :

Ouais ben mon truc il marche bien


Oui oui [:pingouino]

MagicBuzz a écrit :

et c'est pas du repompage d'un site :o


C'est pas du repompage, c'est l'utilisation de l'effort des autres mis à dispo du public (ce qui est le rôle de codeproject). En d'autres termes, c'est être intelligent. Sans compter que le truc codeproject effectue la conversion entre des bases totalement arbitraires.

MagicBuzz a écrit :

Et à l'utilisation, tu gardes ta valeur dans ta base, tu passes pas par des strings à tout bout de champ :spamafote:


Il y a aussi des classes de bases plus ou moins arbitraires sur codeproj, mais c'est clairement pas ce que demande creusois [:spamafote]


Message édité par masklinn le 30-07-2008 à 15:11:13

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 30-07-2008 à 14:26:47    

il veut convertir un array de char en long en respectant la base 36, ce que fait mon code.
 
celui de code projet permet de convertir une string en string en changeant la baseutilisée pour représentation, ce qui ne correspond pas à ce qu'il veut
 
(non mais :o)

Reply

Marsh Posté le 30-07-2008 à 14:26:47   

Reply

Marsh Posté le 30-07-2008 à 15:33:44    

MagicBuzz a écrit :

il veut convertir un array de char en long en respectant la base 36, ce que fait mon code.
 
celui de code projet permet de convertir une string en string en changeant la baseutilisée pour représentation, ce qui ne correspond pas à ce qu'il veut
 
(non mais :o)


 
Je vois que mon post dechaine les passions. J'ai réussi à faire ce que je voulais ne le codant à la mano, mais je pense que j'ai pas fait la meilleur méthode (surtout dans les toString() et les parse par dessus. J'ai un peu de mal dans les conversion de byte en char.
 
Voici ma fonction
 

Code :
  1. public long parseBase(char[] str)
  2.         {
  3.             Dictionary<char,int> tabCorrespondance = new Dictionary<char,int>();
  4.             tabCorrespondance.Add('0', 0);
  5.             tabCorrespondance.Add('1', 1);
  6.             tabCorrespondance.Add('2', 2);
  7.             tabCorrespondance.Add('3', 3);
  8.             tabCorrespondance.Add('4', 4);
  9.             tabCorrespondance.Add('5', 5);
  10.             tabCorrespondance.Add('6', 6);
  11.             tabCorrespondance.Add('7', 7);
  12.             tabCorrespondance.Add('8', 8);
  13.             tabCorrespondance.Add('9', 9);
  14.             tabCorrespondance.Add('a', 10);
  15.             tabCorrespondance.Add('b', 11);
  16.             tabCorrespondance.Add('c', 12);
  17.             tabCorrespondance.Add('d', 13);
  18.             tabCorrespondance.Add('e', 14);
  19.             tabCorrespondance.Add('f', 15);
  20.             tabCorrespondance.Add('g', 16);
  21.             tabCorrespondance.Add('h', 17);
  22.             tabCorrespondance.Add('i', 18);
  23.             tabCorrespondance.Add('j', 19);
  24.             tabCorrespondance.Add('k', 20);
  25.             tabCorrespondance.Add('l', 21);
  26.             tabCorrespondance.Add('m', 22);
  27.             tabCorrespondance.Add('n', 23);
  28.             tabCorrespondance.Add('o', 24);
  29.             tabCorrespondance.Add('p', 25);
  30.             tabCorrespondance.Add('q', 26);
  31.             tabCorrespondance.Add('r', 27);
  32.             tabCorrespondance.Add('s', 28);
  33.             tabCorrespondance.Add('t', 29);
  34.             tabCorrespondance.Add('u', 30);
  35.             tabCorrespondance.Add('v', 31);
  36.             tabCorrespondance.Add('w', 32);
  37.             tabCorrespondance.Add('x', 33);
  38.             tabCorrespondance.Add('y', 34);
  39.             tabCorrespondance.Add('z', 35);
  40.             Array.Reverse(str);
  41.             long nb = 0;
  42.             double scale = 0;
  43.             foreach (char var in str)
  44.             {
  45.                 if (scale == 0)
  46.                 {
  47.                     nb += tabCorrespondance[var];
  48.                 }
  49.                 else
  50.                 {
  51.                     nb += long.Parse(Math.Pow(double.Parse("36" ), scale).ToString()) * tabCorrespondance[var];
  52.                 }
  53.                 scale++;
  54.             }
  55.             return nb;
  56. }

Reply

Marsh Posté le 03-08-2008 à 20:46:25    

creusois a écrit :

 
Code :
  1. {                 
  2.                     nb += long.Parse(Math.Pow(double.Parse("36" ), scale).ToString()) * tabCorrespondance[var];
  3.                 }



[:pingouino]


Message édité par TotalRecall le 03-08-2008 à 20:46:46

---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 04-08-2008 à 00:33:52    

c vrai que j'avais pas fait gaffe à sa façon de faire des cast explicits :D

Reply

Marsh Posté le 04-08-2008 à 00:49:53    

Sinon, pour info aussi, même si c'est plus de la bidouille sauce C que de l'algo "propre", le coup du dictionnaire qui fait 36 lignes et doit bouffer au bas mot 1 Ko de mémoire inutilement se gère très bien de cette façon old school :
 

Code :
  1. public const string EnumDigits = "0123456789abcdefghijklmnopqrstuvwxyz";


 
puis à l'utilisation :

Code :
  1. char ChiffreBase36 = EnumDigits[ValeurEntiere];
  2. int ValeurEntiere = EnumDigits.indexOf(ChiffreBase36);


 
L'astuce, c'est qu'une chaîne de caractères, c'est ni plus ni moins qu'un tableau de char. Le C# conserve donc cette possibilité offerte en C/C++ d'adresser directement un char à l'intérieur d'un string d'après sa position comme si on avait déclaré explicitement un char[]. Niveau perfs, y'a pas photo la première ligne sera infiniment plus rapide que de passer par un dictionnaire. Quant à la seconde, ce sera au pire aussi lent. Dans tous les cas, ça consomme 36 octets en mémoire (plus quelques pouillèmes à cause du type String qui est un objet)
 
 
Et pour en revenir au cast explicite :
 

Code :
  1. long MonLong = (long)MonInt;
  2. long MonLong = (long)MonDouble;
  3.  
  4. double MonDouble = (double)MonLong / (double)Monentier;


 
infiniment plus rapide à l'excécution (surtout pour les cast entre int et long qui ont rigougeusement la même représentation au niveau processeur, seul le nombre de registres change, qui est même implicite) :
 

Code :
  1. long MonLong = MonInt;
  2. int MonEntier = MonLong;


 
 
Donc :

Code :
  1. nb += long.Parse(Math.Pow(double.Parse("36" ), scale).ToString()) * tabCorrespondance[var];


 
Devient :

Code :
  1. nb += (long)Math.Pow(36, scale) * tabCorrespondance[var];


 
pas besoin de caster "36", puisqu'une valeur litérale est typée à la compilation avec le type attendu. Il sera déduit du prototype compatible de Math.Pow(?, TypeDe"scale" )
 
En gros, la fonction devient (à 1h du mat, me lourdez pas si ça compile pas :D)

Code :
  1. string const Digits = "0123456789abcdefghijklmnopqrstuvwxyz";
  2.  
  3. public long parseBase(char[] str)
  4. {
  5.  long nb = 0;
  6.  double scale = 0;
  7.  
  8.  for (int i = str.Length - 1; i >= 0; i--)
  9.  {
  10.    nb += (long)Math.Pow(scale++, 36) * Digits.IndexOf(str[i]);
  11.  }
  12.  return nb;
  13. }


 
C un peu plus concis :o


Message édité par MagicBuzz le 04-08-2008 à 01:07:11
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed