문제

나는 숫자를 가져 와서 어떤 기초로 변환하는 오래된 (ish) c# 방법을 가지고 있습니다.

string ConvertToBase(int number, char[] baseChars);

슈퍼 빠르고 깔끔한 것은 아닙니다. .NET에서 이것을 달성하는 좋은 잘 알려진 방법이 있습니까?

나는 내가 사용할 수있는 것을 찾고 있습니다 어느 사용할 캐릭터 문자열이있는베이스.

이것은 기지 16, 10, 8 및 2 만 허용합니다.

Convert.ToString(1, x);

나는 이것을 사용하여 숫자, 모든 소문자 및 모든 대문자를 활용하는 대규모 높은 기지를 달성하고 싶습니다. in처럼 이 스레드, 그러나 C#은 JavaScript가 아닙니다.

C#에서이 작업을 수행하는 좋은 방법을 아는 사람이 있습니까?

도움이 되었습니까?

해결책

Convert.ToString 지정된베이스에서 숫자를 동등한 문자열 표현으로 변환하는 데 사용할 수 있습니다.

예시:

string binary = Convert.ToString(5, 2); // convert 5 to its binary representation
Console.WriteLine(binary);              // prints 101

그러나 의견에서 지적한대로 Convert.ToString 2, 8, 10 또는 16의 한계 (일반적으로 충분한) 기준 세트 만 지원합니다.

업데이트 (모든 기반으로 변환하기위한 요구 사항을 충족시키기 위해) :

나는 숫자를 모든 기반으로 변환 할 수있는 BCL의 방법을 알지 못하므로 자신의 작은 유틸리티 기능을 작성해야합니다. 간단한 샘플은 그와 같을 것입니다 (문자열 연결을 교체하여 더 빨리 만들 수 있음) :

class Program
{
    static void Main(string[] args)
    {
        // convert to binary
        string binary = IntToString(42, new char[] { '0', '1' });

        // convert to hexadecimal
        string hex = IntToString(42, 
            new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                         'A', 'B', 'C', 'D', 'E', 'F'});

        // convert to hexavigesimal (base 26, A-Z)
        string hexavigesimal = IntToString(42, 
            Enumerable.Range('A', 26).Select(x => (char)x).ToArray());

        // convert to sexagesimal
        string xx = IntToString(42, 
            new char[] { '0','1','2','3','4','5','6','7','8','9',
            'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
            'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x'});
    }

    public static string IntToString(int value, char[] baseChars)
    {
        string result = string.Empty;
        int targetBase = baseChars.Length;

        do
        {
            result = baseChars[value % targetBase] + result;
            value = value / targetBase;
        } 
        while (value > 0);

        return result;
    }

    /// <summary>
    /// An optimized method using an array as buffer instead of 
    /// string concatenation. This is faster for return values having 
    /// a length > 1.
    /// </summary>
    public static string IntToStringFast(int value, char[] baseChars)
    {
        // 32 is the worst cast buffer size for base 2 and int.MaxValue
        int i = 32;
        char[] buffer = new char[i];
        int targetBase= baseChars.Length;

        do
        {
            buffer[--i] = baseChars[value % targetBase];
            value = value / targetBase;
        }
        while (value > 0);

        char[] result = new char[32 - i];
        Array.Copy(buffer, i, result, 0, 32 - i);

        return new string(result);
    }
}

업데이트 2 (성능 향상)

문자열 연결 대신 배열 버퍼를 사용하여 결과 문자열을 구축하면 특히 많은 수의 성능 향상이 제공됩니다 (메소드 참조 IntToStringFast). 최선의 경우 (예 : 가장 긴 입력)이 방법은 대략 3 배 더 빠릅니다. 그러나 1 자리 숫자 (즉, 대상 기반의 1 자리)의 경우, IntToString 더 빨라질 것입니다.

다른 팁

나는 최근에 이것에 대해 블로그를 작성했다. 내 구현은 계산 중에 문자열 작업을 사용하지 않으므로 매우 빠릅니다. 2에서 36의베이스가있는 숫자 시스템으로 변환이 지원됩니다.

/// <summary>
/// Converts the given decimal number to the numeral system with the
/// specified radix (in the range [2, 36]).
/// </summary>
/// <param name="decimalNumber">The number to convert.</param>
/// <param name="radix">The radix of the destination numeral system (in the range [2, 36]).</param>
/// <returns></returns>
public static string DecimalToArbitrarySystem(long decimalNumber, int radix)
{
    const int BitsInLong = 64;
    const string Digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    if (radix < 2 || radix > Digits.Length)
        throw new ArgumentException("The radix must be >= 2 and <= " + Digits.Length.ToString());

    if (decimalNumber == 0)
        return "0";

    int index = BitsInLong - 1;
    long currentNumber = Math.Abs(decimalNumber);
    char[] charArray = new char[BitsInLong];

    while (currentNumber != 0)
    {
        int remainder = (int)(currentNumber % radix);
        charArray[index--] = Digits[remainder];
        currentNumber = currentNumber / radix;
    }

    string result = new String(charArray, index + 1, BitsInLong - index - 1);
    if (decimalNumber < 0)
    {
        result = "-" + result;
    }

    return result;
}

또한 누구나 필요한 경우에도 빠른 역 기능을 구현했습니다.십진수 숫자 시스템에 임의적입니다.

빠른 "에서" 그리고 "에게"방법

나는 파티에 늦었지만, 나는 이전의 답변을 복잡하게 만들고 그것들을 향상시켰다. 이 두 가지 방법은 지금까지 게시 한 다른 방법보다 빠르다고 생각합니다. 단일 코어 머신에서 400ms 미만으로 1,000,000 숫자를 400ms 미만으로 변환 할 수있었습니다.

아래의 예는 다음과 같습니다 기본 62. 변경 BaseChars 다른 기지에서 그리고 다른 기지로 변환 할 배열.

private static readonly char[] BaseChars = 
         "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
private static readonly Dictionary<char, int> CharValues = BaseChars
           .Select((c,i)=>new {Char=c, Index=i})
           .ToDictionary(c=>c.Char,c=>c.Index);

public static string LongToBase(long value)
{
   long targetBase = BaseChars.Length;
   // Determine exact number of characters to use.
   char[] buffer = new char[Math.Max( 
              (int) Math.Ceiling(Math.Log(value + 1, targetBase)), 1)];

   var i = buffer.Length;
   do
   {
       buffer[--i] = BaseChars[value % targetBase];
       value = value / targetBase;
   }
   while (value > 0);

   return new string(buffer, i, buffer.Length - i);
}

public static long BaseToLong(string number) 
{ 
    char[] chrs = number.ToCharArray(); 
    int m = chrs.Length - 1; 
    int n = BaseChars.Length, x;
    long result = 0; 
    for (int i = 0; i < chrs.Length; i++)
    {
        x = CharValues[ chrs[i] ];
        result += x * (long)Math.Pow(n, m--);
    }
    return result;  
} 

편집 (2018-07-12)

46655를 기본 36으로 변환하는 @adrianbotor (주석 참조)가 찾은 코너 케이스를 해결하기 위해 수정되었습니다. 이것은 작은 부동 소수점 오류 계산으로 인해 발생합니다. Math.Log(46656, 36) 정확히 3이지만 .NET은 반환합니다 3 + 4.44e-16, 출력 버퍼에 추가 문자가 발생합니다.

허용 된 사람의 약간 수정 된 버전을 사용하고 기본 문자를 조정할 수도 있습니다.

public static string Int32ToString(int value, int toBase)
{
    string result = string.Empty;
    do
    {
        result = "0123456789ABCDEF"[value % toBase] + result;
        value /= toBase;
    }
    while (value > 0);

    return result;
}

이 파티에 매우 늦었지만 최근에 직장 프로젝트에 대한 다음 도우미 수업을 썼습니다. 짧은 문자열을 숫자로 변환하고 다시 뒤로 변환하도록 설계되었습니다 (단순한 완벽한 해시 기능) 그러나 임의의 기반 사이의 숫자 변환도 수행합니다. 그만큼 Base10ToString 메소드 구현은 원래 게시 된 질문에 답변합니다.

그만큼 shouldSupportRoundTripping 클래스 생성자에게 전달 된 플래그는베이스 -10으로 전환하는 동안 숫자 문자열에서 선행 숫자의 손실이 손실되는 것을 방지하기 위해 필요합니다 (내 요구 사항에 따라 중요합니다!). 대부분의 경우 숫자 문자열에서 주요 0의 손실은 아마도 문제가되지 않을 것입니다.

어쨌든 여기 코드가 있습니다.

using System;
using System.Collections.Generic;
using System.Linq;

namespace StackOverflow
{
    /// <summary>
    /// Contains methods used to convert numbers between base-10 and another numbering system.
    /// </summary>
    /// <remarks>
    /// <para>
    /// This conversion class makes use of a set of characters that represent the digits used by the target
    /// numbering system. For example, binary would use the digits 0 and 1, whereas hex would use the digits
    /// 0 through 9 plus A through F. The digits do not have to be numerals.
    /// </para>
    /// <para>
    /// The first digit in the sequence has special significance. If the number passed to the
    /// <see cref="StringToBase10"/> method has leading digits that match the first digit, then those leading
    /// digits will effectively be 'lost' during conversion. Much of the time this won't matter. For example,
    /// "0F" hex will be converted to 15 decimal, but when converted back to hex it will become simply "F",
    /// losing the leading "0". However, if the set of digits was A through Z, and the number "ABC" was
    /// converted to base-10 and back again, then the leading "A" would be lost. The <see cref="System.Boolean"/>
    /// flag passed to the constructor allows 'round-tripping' behaviour to be supported, which will prevent
    /// leading digits from being lost during conversion.
    /// </para>
    /// <para>
    /// Note that numeric overflow is probable when using longer strings and larger digit sets.
    /// </para>
    /// </remarks>
    public class Base10Converter
    {
        const char NullDigit = '\0';

        public Base10Converter(string digits, bool shouldSupportRoundTripping = false)
            : this(digits.ToCharArray(), shouldSupportRoundTripping)
        {
        }

        public Base10Converter(IEnumerable<char> digits, bool shouldSupportRoundTripping = false)
        {
            if (digits == null)
            {
                throw new ArgumentNullException("digits");
            }

            if (digits.Count() == 0)
            {
                throw new ArgumentException(
                    message: "The sequence is empty.",
                    paramName: "digits"
                    );
            }

            if (!digits.Distinct().SequenceEqual(digits))
            {
                throw new ArgumentException(
                    message: "There are duplicate characters in the sequence.",
                    paramName: "digits"
                    );
            }

            if (shouldSupportRoundTripping)
            {
                digits = (new[] { NullDigit }).Concat(digits);
            }

            _digitToIndexMap =
                digits
                .Select((digit, index) => new { digit, index })
                .ToDictionary(keySelector: x => x.digit, elementSelector: x => x.index);

            _radix = _digitToIndexMap.Count;

            _indexToDigitMap =
                _digitToIndexMap
                .ToDictionary(keySelector: x => x.Value, elementSelector: x => x.Key);
        }

        readonly Dictionary<char, int> _digitToIndexMap;
        readonly Dictionary<int, char> _indexToDigitMap;
        readonly int _radix;

        public long StringToBase10(string number)
        {
            Func<char, int, long> selector =
                (c, i) =>
                {
                    int power = number.Length - i - 1;

                    int digitIndex;
                    if (!_digitToIndexMap.TryGetValue(c, out digitIndex))
                    {
                        throw new ArgumentException(
                            message: String.Format("Number contains an invalid digit '{0}' at position {1}.", c, i),
                            paramName: "number"
                            );
                    }

                    return Convert.ToInt64(digitIndex * Math.Pow(_radix, power));
                };

            return number.Select(selector).Sum();
        }

        public string Base10ToString(long number)
        {
            if (number < 0)
            {
                throw new ArgumentOutOfRangeException(
                    message: "Value cannot be negative.",
                    paramName: "number"
                    );
            }

            string text = string.Empty;

            long remainder;
            do
            {
                number = Math.DivRem(number, _radix, out remainder);

                char digit;
                if (!_indexToDigitMap.TryGetValue((int) remainder, out digit) || digit == NullDigit)
                {
                    throw new ArgumentException(
                        message: "Value cannot be converted given the set of digits used by this converter.",
                        paramName: "number"
                        );
                }

                text = digit + text;
            }
            while (number > 0);

            return text;
        }
    }
}

또한 사용자 정의 번호 변환기를 도출하기 위해 서브 클래스를 만들 수도 있습니다.

namespace StackOverflow
{
    public sealed class BinaryNumberConverter : Base10Converter
    {
        public BinaryNumberConverter()
            : base(digits: "01", shouldSupportRoundTripping: false)
        {
        }
    }

    public sealed class HexNumberConverter : Base10Converter
    {
        public HexNumberConverter()
            : base(digits: "0123456789ABCDEF", shouldSupportRoundTripping: false)
        {
        }
    }
}

코드는 다음과 같이 사용됩니다.

using System.Diagnostics;

namespace StackOverflow
{
    class Program
    {
        static void Main(string[] args)
        {
            {
                var converter = new Base10Converter(
                    digits: "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz",
                    shouldSupportRoundTripping: true
                    );

                long number = converter.StringToBase10("Atoz");
                string text = converter.Base10ToString(number);
                Debug.Assert(text == "Atoz");
            }

            {
                var converter = new HexNumberConverter();

                string text = converter.Base10ToString(255);
                long number = converter.StringToBase10(text);
                Debug.Assert(number == 255);
            }
        }
    }
}

이 수업에서 이 포럼 게시물 도와주세요?

public class BaseConverter { 

public static string ToBase(string number, int start_base, int target_base) { 

  int base10 = this.ToBase10(number, start_base); 
  string rtn = this.FromBase10(base10, target_base); 
  return rtn; 

} 

public static int ToBase10(string number, int start_base) { 

  if (start_base < 2 || start_base > 36) return 0; 
  if (start_base == 10) return Convert.ToInt32(number); 

  char[] chrs = number.ToCharArray(); 
  int m = chrs.Length - 1; 
  int n = start_base; 
  int x; 
  int rtn = 0; 

  foreach(char c in chrs) { 

    if (char.IsNumber(c)) 
      x = int.Parse(c.ToString()); 
    else 
      x = Convert.ToInt32(c) - 55; 

    rtn += x * (Convert.ToInt32(Math.Pow(n, m))); 

    m--; 

  } 

  return rtn; 

} 

public static string FromBase10(int number, int target_base) { 

  if (target_base < 2 || target_base > 36) return ""; 
  if (target_base == 10) return number.ToString(); 

  int n = target_base; 
  int q = number; 
  int r; 
  string rtn = ""; 

  while (q >= n) { 

    r = q % n; 
    q = q / n; 

    if (r < 10) 
      rtn = r.ToString() + rtn; 
    else 
      rtn = Convert.ToChar(r + 55).ToString() + rtn; 

  } 

  if (q < 10) 
    rtn = q.ToString() + rtn; 
  else 
    rtn = Convert.ToChar(q + 55).ToString() + rtn; 

  return rtn; 

} 

}

완전히 테스트되지 않은 ... 작동하는지 알려주세요! (포럼 게시물이 사라지는 경우를 대비하여 복사했습니다 ...)

나도 10 진수를 [2..36]의 범위에서 다른베이스로 변환하는 빠른 방법을 찾고 있었기 때문에 다음 코드를 개발했습니다. 문자별로 문자를 색인화 할 수있는 문자 버퍼의 프록시로 StringBuilder 객체를 따라 간단하고 StringBuilder 개체를 사용합니다. 코드는 대안에 비해 매우 빠르며 문자 배열에서 개별 문자를 초기화하는 것보다 훨씬 빠릅니다.

자신의 용도로 다음을 선호 할 수 있습니다. 1/ 예외를 던지지 않고 빈 문자열을 반환합니다. 2/ radix 검사를 제거하려면 메소드가 더 빨리 실행되도록 32 '0으로 StringBuilder 객체를 초기화하고 라인 결과를 제거합니다 .remove (0, i);. 이로 인해 스트링은 주요 0으로 반환되고 속도를 더욱 증가시킵니다. 4/ StringBuilder 객체를 클래스 내 정적 필드로 만드십시오. DecimalTobase 방법을 몇 배에 상관없이 StringBuilder 객체라고 불리는 경우에만 한 번만 초기화됩니다. 이 변경을 수행하면 위의 변경 3은 더 이상 작동하지 않습니다.

나는 누군가가 이것을 유용하다는 것을 알기를 바랍니다. :)

Atomicparadox

        static string DecimalToBase(int number, int radix)
    {
        // Check that the radix is between 2 and 36 inclusive
        if ( radix < 2 || radix > 36 )
            throw new ArgumentException("ConvertToBase(int number, int radix) - Radix must be between 2 and 36.");

        // Create a buffer large enough to hold the largest int value represented in binary digits 
        StringBuilder result = new StringBuilder("                                ");  // 32 spaces

        // The base conversion calculates the digits in reverse order so use
        // an index to point to the last unused space in our buffer
        int i = 32; 

        // Convert the number to the new base
        do
        {
            int remainder = number % radix;
            number = number / radix;
            if(remainder <= 9)
                result[--i] = (char)(remainder + '0');  // Converts [0..9] to ASCII ['0'..'9']
            else
                result[--i] = (char)(remainder + '7');  // Converts [10..36] to ASCII ['A'..'Z']
        } while ( number > 0 );

        // Remove the unwanted padding from the front of our buffer and return the result
        // Note i points to the last unused character in our buffer
        result.Remove( 0, i );
        return (result.ToString());
    }

나는 이것을 더 짧은 문자열로 저장하기 위해 이것을 사용하고 있었지만 (106자를 사용하는 것으로 제한). 여기에 관심이 있다면 여기에 문자열을 숫자 값으로 다시 디코딩하는 코드가 있습니다 (이 경우 int128을 코딩하는 대신 GUID 값에 2 개의 Ulongs를 사용했습니다 (4.0이 아닌 3.5이므로). Clarity Code의 경우는 A입니다. 106 고유 한 숯이있는 문자열 const. ConvertLongstobytes는 꽤 흥분합니다.

private static Guid B106ToGuid(string pStr)
    {
        try
        {
            ulong tMutl = 1, tL1 = 0, tL2 = 0, targetBase = (ulong)CODE.Length;
            for (int i = 0; i < pStr.Length / 2; i++)
            {
                tL1 += (ulong)CODE.IndexOf(pStr[i]) * tMutl;
                tL2 += (ulong)CODE.IndexOf(pStr[pStr.Length / 2 + i]) * tMutl;
                tMutl *= targetBase;
            }
            return new Guid(ConvertLongsToBytes(tL1, tL2));
        }
        catch (Exception ex)
        {
            throw new Exception("B106ToGuid failed to convert string to Guid", ex);
        }
    }

나는 "숫자"에서도 수학을해야한다는 점을 제외하고는 비슷한 요구가있었습니다. 나는 여기서 몇 가지 제안을 했고이 모든 재미있는 일을 할 수업을 만들었습니다. 그것은 숫자를 나타내는 데 유니 코드 문자를 사용할 수 있으며 소수점과도 작동합니다.

이 수업은 사용하기 쉽습니다. 숫자를 유형으로 만듭니다 New BaseNumber, 몇 가지 속성을 설정하고 꺼짐. 루틴은베이스 10과베이스 X 사이의 전환을 자동으로 처리하고 설정 한베이스에 설정된 값이 보존되므로 정확도가 손실되지 않으므로 (변환 될 때까지도 정밀 손실도 매우 최소화되어야합니다. 일상적인 용도 Double 그리고 Long 가능한 곳).

나는이 루틴의 속도를 명령 할 수 없다. 아마도 매우 느리기 때문에 질문을 한 사람의 요구에 맞는지 확실하지 않지만 확실히 유연하기 때문에 다른 사람이 이것을 사용할 수 있기를 바랍니다.

Excel에서 다음 열을 계산하기 위해이 코드가 필요한 다른 사람의 경우이 클래스를 활용하는 루핑 코드를 포함합니다.

Public Class BaseNumber

    Private _CharacterArray As List(Of Char)

    Private _BaseXNumber As String
    Private _Base10Number As Double?

    Private NumberBaseLow As Integer
    Private NumberBaseHigh As Integer

    Private DecimalSeparator As Char = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator
    Private GroupSeparator As Char = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator

    Public Sub UseCapsLetters()
        'http://unicodelookup.com
        TrySetBaseSet(65, 90)
    End Sub

    Public Function GetCharacterArray() As List(Of Char)
        Return _CharacterArray
    End Function

    Public Sub SetCharacterArray(CharacterArray As String)
        _CharacterArray = New List(Of Char)
        _CharacterArray.AddRange(CharacterArray.ToList)

        TrySetBaseSet(_CharacterArray)
    End Sub

    Public Sub SetCharacterArray(CharacterArray As List(Of Char))
        _CharacterArray = CharacterArray
        TrySetBaseSet(_CharacterArray)
    End Sub

    Public Sub SetNumber(Value As String)
        _BaseXNumber = Value
        _Base10Number = Nothing
    End Sub

    Public Sub SetNumber(Value As Double)
        _Base10Number = Value
        _BaseXNumber = Nothing
    End Sub

    Public Function GetBaseXNumber() As String
        If _BaseXNumber IsNot Nothing Then
            Return _BaseXNumber
        Else
            Return ToBaseString()
        End If
    End Function

    Public Function GetBase10Number() As Double
        If _Base10Number IsNot Nothing Then
            Return _Base10Number
        Else
            Return ToBase10()
        End If
    End Function

    Private Sub TrySetBaseSet(Values As List(Of Char))
        For Each value As Char In _BaseXNumber
            If Not Values.Contains(value) Then
                Throw New ArgumentOutOfRangeException("The string has a value, " & value & ", not contained in the selected 'base' set.")
                _CharacterArray.Clear()
                DetermineNumberBase()
            End If
        Next

        _CharacterArray = Values

    End Sub

    Private Sub TrySetBaseSet(LowValue As Integer, HighValue As Integer)

        Dim HighLow As KeyValuePair(Of Integer, Integer) = GetHighLow()

        If HighLow.Key < LowValue OrElse HighLow.Value > HighValue Then
            Throw New ArgumentOutOfRangeException("The string has a value not contained in the selected 'base' set.")
            _CharacterArray.Clear()
            DetermineNumberBase()
        End If

        NumberBaseLow = LowValue
        NumberBaseHigh = HighValue

    End Sub

    Private Function GetHighLow(Optional Values As List(Of Char) = Nothing) As KeyValuePair(Of Integer, Integer)
        If Values Is Nothing Then
            Values = _BaseXNumber.ToList
        End If

        Dim lowestValue As Integer = Convert.ToInt32(Values(0))
        Dim highestValue As Integer = Convert.ToInt32(Values(0))

        Dim currentValue As Integer

        For Each value As Char In Values

            If value <> DecimalSeparator AndAlso value <> GroupSeparator Then
                currentValue = Convert.ToInt32(value)
                If currentValue > highestValue Then
                    highestValue = currentValue
                End If
                If currentValue < lowestValue Then
                    currentValue = lowestValue
                End If
            End If
        Next

        Return New KeyValuePair(Of Integer, Integer)(lowestValue, highestValue)

    End Function

    Public Sub New(BaseXNumber As String)
        _BaseXNumber = BaseXNumber
        DetermineNumberBase()
    End Sub

    Public Sub New(BaseXNumber As String, NumberBase As Integer)
        Me.New(BaseXNumber, Convert.ToInt32("0"c), NumberBase)
    End Sub

    Public Sub New(BaseXNumber As String, NumberBaseLow As Integer, NumberBaseHigh As Integer)
        _BaseXNumber = BaseXNumber
        Me.NumberBaseLow = NumberBaseLow
        Me.NumberBaseHigh = NumberBaseHigh
    End Sub

    Public Sub New(Base10Number As Double)
        _Base10Number = Base10Number
    End Sub

    Private Sub DetermineNumberBase()
        Dim highestValue As Integer

        Dim currentValue As Integer

        For Each value As Char In _BaseXNumber

            currentValue = Convert.ToInt32(value)
            If currentValue > highestValue Then
                highestValue = currentValue
            End If
        Next

        NumberBaseHigh = highestValue
        NumberBaseLow = Convert.ToInt32("0"c) 'assume 0 is the lowest

    End Sub

    Private Function ToBaseString() As String
        Dim Base10Number As Double = _Base10Number

        Dim intPart As Long = Math.Truncate(Base10Number)
        Dim fracPart As Long = (Base10Number - intPart).ToString.Replace(DecimalSeparator, "")

        Dim intPartString As String = ConvertIntToString(intPart)
        Dim fracPartString As String = If(fracPart <> 0, DecimalSeparator & ConvertIntToString(fracPart), "")

        Return intPartString & fracPartString

    End Function

    Private Function ToBase10() As Double
        Dim intPartString As String = _BaseXNumber.Split(DecimalSeparator)(0).Replace(GroupSeparator, "")
        Dim fracPartString As String = If(_BaseXNumber.Contains(DecimalSeparator), _BaseXNumber.Split(DecimalSeparator)(1), "")

        Dim intPart As Long = ConvertStringToInt(intPartString)
        Dim fracPartNumerator As Long = ConvertStringToInt(fracPartString)
        Dim fracPartDenominator As Long = ConvertStringToInt(GetEncodedChar(1) & String.Join("", Enumerable.Repeat(GetEncodedChar(0), fracPartString.ToString.Length)))

        Return Convert.ToDouble(intPart + fracPartNumerator / fracPartDenominator)

    End Function

    Private Function ConvertIntToString(ValueToConvert As Long) As String
        Dim result As String = String.Empty
        Dim targetBase As Long = GetEncodingCharsLength()

        Do
            result = GetEncodedChar(ValueToConvert Mod targetBase) & result
            ValueToConvert = ValueToConvert \ targetBase
        Loop While ValueToConvert > 0

        Return result
    End Function

    Private Function ConvertStringToInt(ValueToConvert As String) As Long
        Dim result As Long
        Dim targetBase As Integer = GetEncodingCharsLength()
        Dim startBase As Integer = GetEncodingCharsStartBase()

        Dim value As Char
        For x As Integer = 0 To ValueToConvert.Length - 1
            value = ValueToConvert(x)
            result += GetDecodedChar(value) * Convert.ToInt32(Math.Pow(GetEncodingCharsLength, ValueToConvert.Length - (x + 1)))
        Next

        Return result

    End Function

    Private Function GetEncodedChar(index As Integer) As Char
        If _CharacterArray IsNot Nothing AndAlso _CharacterArray.Count > 0 Then
            Return _CharacterArray(index)
        Else
            Return Convert.ToChar(index + NumberBaseLow)
        End If
    End Function

    Private Function GetDecodedChar(character As Char) As Integer
        If _CharacterArray IsNot Nothing AndAlso _CharacterArray.Count > 0 Then
            Return _CharacterArray.IndexOf(character)
        Else
            Return Convert.ToInt32(character) - NumberBaseLow
        End If
    End Function

    Private Function GetEncodingCharsLength() As Integer
        If _CharacterArray IsNot Nothing AndAlso _CharacterArray.Count > 0 Then
            Return _CharacterArray.Count
        Else
            Return NumberBaseHigh - NumberBaseLow + 1
        End If
    End Function

    Private Function GetEncodingCharsStartBase() As Integer
        If _CharacterArray IsNot Nothing AndAlso _CharacterArray.Count > 0 Then
            Return GetHighLow.Key
        Else
            Return NumberBaseLow
        End If
    End Function
End Class

그리고 이제 코드가 Excel 열을 통해 루프 할 수 있습니다.

    Public Function GetColumnList(DataSheetID As String) As List(Of String)
        Dim workingColumn As New BaseNumber("A")
        workingColumn.SetCharacterArray("@ABCDEFGHIJKLMNOPQRSTUVWXYZ")

        Dim listOfPopulatedColumns As New List(Of String)
        Dim countOfEmptyColumns As Integer

        Dim colHasData As Boolean
        Dim cellHasData As Boolean

        Do
            colHasData = True
            cellHasData = False
            For r As Integer = 1 To GetMaxRow(DataSheetID)
                cellHasData = cellHasData Or XLGetCellValue(DataSheetID, workingColumn.GetBaseXNumber & r) <> ""
            Next
            colHasData = colHasData And cellHasData

            'keep trying until we get 4 empty columns in a row
            If colHasData Then
                listOfPopulatedColumns.Add(workingColumn.GetBaseXNumber)
                countOfEmptyColumns = 0
            Else
                countOfEmptyColumns += 1
            End If

            'we are already starting with column A, so increment after we check column A
            Do
                workingColumn.SetNumber(workingColumn.GetBase10Number + 1)
            Loop Until Not workingColumn.GetBaseXNumber.Contains("@")

        Loop Until countOfEmptyColumns > 3

        Return listOfPopulatedColumns

    End Function

Excel 부분의 중요한 부분은 0이 re 기반 숫자에서 @로 식별된다는 것입니다. 그래서 나는 그 안에 @가있는 모든 숫자를 걸러 내고 적절한 시퀀스 (a, b, c, ..., z, aa, ac, ac, ...)를 얻습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConvertToAnyBase
{
   class Program
    {
        static void Main(string[] args)
        {
            var baseNumber = int.Parse(Console.ReadLine());
            var number = int.Parse(Console.ReadLine());
            string conversion = "";


            while(number!=0)
            {

                conversion += Convert.ToString(number % baseNumber);
                number = number / baseNumber;
            }
            var conversion2 = conversion.ToArray().Reverse();
            Console.WriteLine(string.Join("", conversion2));


       }
    }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top