guid 为 base64,用于 URL

发布于 2024-07-25 16:41:16 字数 1086 浏览 4 评论 0原文

问题:有更好的方法吗?

VB.Net

Function GuidToBase64(ByVal guid As Guid) As String
    Return Convert.ToBase64String(guid.ToByteArray).Replace("/", "-").Replace("+", "_").Replace("=", "")
End Function

Function Base64ToGuid(ByVal base64 As String) As Guid
    Dim guid As Guid
    base64 = base64.Replace("-", "/").Replace("_", "+") & "=="

    Try
        guid = New Guid(Convert.FromBase64String(base64))
    Catch ex As Exception
        Throw New Exception("Bad Base64 conversion to GUID", ex)
    End Try

    Return guid
End Function

C#

public string GuidToBase64(Guid guid)
{
    return Convert.ToBase64String(guid.ToByteArray()).Replace("/", "-").Replace("+", "_").Replace("=", "");
}

public Guid Base64ToGuid(string base64)
{
   Guid guid = default(Guid);
   base64 = base64.Replace("-", "/").Replace("_", "+") + "==";

   try {
       guid = new Guid(Convert.FromBase64String(base64));
   }
   catch (Exception ex) {
       throw new Exception("Bad Base64 conversion to GUID", ex);
   }

   return guid;
}

Question: is there a better way to do that?

VB.Net

Function GuidToBase64(ByVal guid As Guid) As String
    Return Convert.ToBase64String(guid.ToByteArray).Replace("/", "-").Replace("+", "_").Replace("=", "")
End Function

Function Base64ToGuid(ByVal base64 As String) As Guid
    Dim guid As Guid
    base64 = base64.Replace("-", "/").Replace("_", "+") & "=="

    Try
        guid = New Guid(Convert.FromBase64String(base64))
    Catch ex As Exception
        Throw New Exception("Bad Base64 conversion to GUID", ex)
    End Try

    Return guid
End Function

C#

public string GuidToBase64(Guid guid)
{
    return Convert.ToBase64String(guid.ToByteArray()).Replace("/", "-").Replace("+", "_").Replace("=", "");
}

public Guid Base64ToGuid(string base64)
{
   Guid guid = default(Guid);
   base64 = base64.Replace("-", "/").Replace("_", "+") + "==";

   try {
       guid = new Guid(Convert.FromBase64String(base64));
   }
   catch (Exception ex) {
       throw new Exception("Bad Base64 conversion to GUID", ex);
   }

   return guid;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

眼眸里的快感 2024-08-01 16:41:16

您可能想查看此网站: http://prettycode.org/2009/11/12/short-guid/

它看起来非常接近你正在做的事情。

public class ShortGuid
{
    private readonly Guid guid;
    private readonly string value;

    /// <summary>Create a 22-character case-sensitive short GUID.</summary>
    public ShortGuid(Guid guid)
    {
        if (guid == null)
        {
            throw new ArgumentNullException("guid");
        }

        this.guid = guid;
        this.value = Convert.ToBase64String(guid.ToByteArray())
            .Substring(0, 22)
            .Replace("/", "_")
            .Replace("+", "-");
    }

    /// <summary>Get the short GUID as a string.</summary>
    public override string ToString()
    {
        return this.value;
    }

    /// <summary>Get the Guid object from which the short GUID was created.</summary>
    public Guid ToGuid()
    {
        return this.guid;
    }

    /// <summary>Get a short GUID as a Guid object.</summary>
    /// <exception cref="System.ArgumentNullException"></exception>
    /// <exception cref="System.FormatException"></exception>
    public static ShortGuid Parse(string shortGuid)
    {
        if (shortGuid == null)
        {
            throw new ArgumentNullException("shortGuid");
        }
        else if (shortGuid.Length != 22)
        {
            throw new FormatException("Input string was not in a correct format.");
        }

        return new ShortGuid(new Guid(Convert.FromBase64String
            (shortGuid.Replace("_", "/").Replace("-", "+") + "==")));
    }

    public static implicit operator String(ShortGuid guid)
    {
        return guid.ToString();
    }

    public static implicit operator Guid(ShortGuid shortGuid)
    {
        return shortGuid.guid;
    }
}

You might want to check out this site: http://prettycode.org/2009/11/12/short-guid/

It looks very close to what you're doing.

public class ShortGuid
{
    private readonly Guid guid;
    private readonly string value;

    /// <summary>Create a 22-character case-sensitive short GUID.</summary>
    public ShortGuid(Guid guid)
    {
        if (guid == null)
        {
            throw new ArgumentNullException("guid");
        }

        this.guid = guid;
        this.value = Convert.ToBase64String(guid.ToByteArray())
            .Substring(0, 22)
            .Replace("/", "_")
            .Replace("+", "-");
    }

    /// <summary>Get the short GUID as a string.</summary>
    public override string ToString()
    {
        return this.value;
    }

    /// <summary>Get the Guid object from which the short GUID was created.</summary>
    public Guid ToGuid()
    {
        return this.guid;
    }

    /// <summary>Get a short GUID as a Guid object.</summary>
    /// <exception cref="System.ArgumentNullException"></exception>
    /// <exception cref="System.FormatException"></exception>
    public static ShortGuid Parse(string shortGuid)
    {
        if (shortGuid == null)
        {
            throw new ArgumentNullException("shortGuid");
        }
        else if (shortGuid.Length != 22)
        {
            throw new FormatException("Input string was not in a correct format.");
        }

        return new ShortGuid(new Guid(Convert.FromBase64String
            (shortGuid.Replace("_", "/").Replace("-", "+") + "==")));
    }

    public static implicit operator String(ShortGuid guid)
    {
        return guid.ToString();
    }

    public static implicit operator Guid(ShortGuid shortGuid)
    {
        return shortGuid.guid;
    }
}
一杆小烟枪 2024-08-01 16:41:16

使用此技术格式化 GUID 以在 URL 或文件名中使用的一个问题是,两个不同的 GUID 可能会生成两个仅大小写不同的值,例如:

    var b1 = GuidToBase64(new Guid("c9d045f3-e21c-46d0-971d-b92ebc2ab83c"));
    var b2 = GuidToBase64(new Guid("c9d045f3-e21c-46d0-971d-b92ebc2ab8a4"));
    Console.WriteLine(b1);  // 80XQyRzi0EaXHbkuvCq4PA
    Console.WriteLine(b2);  // 80XQyRzi0EaXHbkuvCq4pA

由于 URL 有时被解释为不区分大小写,并且在 Windows 文件路径中并且文件名不区分大小写。 这可能会导致碰撞。

One problem with using this technique to format a GUID for use in a URL or filename is that two distinct GUIDs can produce two values that differ only in case, e.g.:

    var b1 = GuidToBase64(new Guid("c9d045f3-e21c-46d0-971d-b92ebc2ab83c"));
    var b2 = GuidToBase64(new Guid("c9d045f3-e21c-46d0-971d-b92ebc2ab8a4"));
    Console.WriteLine(b1);  // 80XQyRzi0EaXHbkuvCq4PA
    Console.WriteLine(b2);  // 80XQyRzi0EaXHbkuvCq4pA

Since URLs are sometimes interpreted as being case-insensitive, and in Windows file paths and filenames are case-insensitive. this could lead to collisions.

桃扇骨 2024-08-01 16:41:16

我知道您最终剪裁 == 的原因是因为您可以确定对于 GUID(16 字节),编码的字符串总是以 == 结尾。 所以每次转换可以节省2个字符。

除了 @Skurmedal 已经提到的点(在输入无效字符串的情况下应该抛出异常),我认为您发布的代码已经足够好了。

I understand that the reason you are clipping == in the end is that because you can be certain that for GUID (of 16 bytes), encoded string will always end with ==. So 2 characters can be saved in every conversion.

Beside the point @Skurmedal already mentioned (should throw an exception in case of invalid string as input), I think the code you posted is just good enough.

骄傲 2024-08-01 16:41:16

在 .NET Core 中,您可以使用 Span 以获得更好的性能并且无需内存分配。

using System.Buffers.Text;
using System.Runtime.InteropServices;

namespace Extensions;

public static class GuidExtensions
{
    private const char Dash = '-';
    private const char EqualsChar = '=';
    private const byte ForwardSlashByte = (byte)Slash;
    private const char Plus = '+';
    private const byte PlusByte = (byte)Plus;
    private const char Slash = '/';
    private const char Underscore = '_';
    private const int Base64LengthWithoutEquals = 22;

    public static string EncodeBase64String(this Guid guid)
    {
        Span<byte> guidBytes = stackalloc byte[16];
        Span<byte> encodedBytes = stackalloc byte[24];

        MemoryMarshal.TryWrite(guidBytes, ref guid);
        Base64.EncodeToUtf8(guidBytes, encodedBytes, out _, out _);

        Span<char> chars = stackalloc char[Base64LengthWithoutEquals];

        // Replace any characters which are not URL safe.
        // And skip the final two bytes as these will be '==' padding we don't need.
        for (int i = 0; i < Base64LengthWithoutEquals; i++)
        {
            chars[i] = encodedBytes[i] switch
            {
                ForwardSlashByte => Dash,
                PlusByte => Underscore,
                _ => (char)encodedBytes[i],
            };
        }

        return new(chars);
    }

    public static Guid DecodeBase64String(this ReadOnlySpan<char> id)
    {
        Span<char> base64Chars = stackalloc char[24];

        for (var i = 0; i < Base64LengthWithoutEquals; i++)
        {
            base64Chars[i] = id[i] switch
            {
                Dash => Slash,
                Underscore => Plus,
                _ => id[i],
            };
        }

        base64Chars[22] = EqualsChar;
        base64Chars[23] = EqualsChar;

        Span<byte> idBytes = stackalloc byte[16];
        Convert.TryFromBase64Chars(base64Chars, idBytes, out _);

        return new(idBytes);
    }
}
using AutoFixture.Xunit2;
using FluentAssertions;
using Extensions;
using Xunit;

namespace ExtensionTests;

public class GuidExtensionsTests
{
    private const int Base64LengthWithoutEquals = 22;
    private const string EmptyBase64 = "AAAAAAAAAAAAAAAAAAAAAA";

    [Theory]
    [AutoData]
    public void EncodeBase64String_DecodeBase64String_Should_ReturnInitialGuid(Guid guid)
    {
        string actualBase64 = guid.EncodeBase64String();
        actualBase64.Should().NotBe(string.Empty)
            .And.HaveLength(Base64LengthWithoutEquals);

        Guid actualGuid = ((ReadOnlySpan<char>)actualBase64).DecodeBase64String();
        actualGuid.Should().Be(guid);
    }

    [Theory]
    [InlineData(EmptyBase64)]
    public void EncodeBase64String_Should_ReturnEmptyBase64_When_GuidIsEmpty(string expected)
    {
        string actualBase64 = Guid.Empty.EncodeBase64String();
        actualBase64.Should().Be(expected);
    }

    [Theory]
    [InlineData(EmptyBase64)]
    public void DecodeBase64String_Should_ReturnEmptyGuid_When_StringIsEmptyBase64(string base64)
    {
        Guid actual = ((ReadOnlySpan<char>)base64).DecodeBase64String();
        actual.Should().Be(Guid.Empty);
    }
}

有关使用 对 guid 进行 Base64 编码的高性能技术,以及非常好的视频说明

In .NET Core you can use Spans for better performance and no memory allocation.

using System.Buffers.Text;
using System.Runtime.InteropServices;

namespace Extensions;

public static class GuidExtensions
{
    private const char Dash = '-';
    private const char EqualsChar = '=';
    private const byte ForwardSlashByte = (byte)Slash;
    private const char Plus = '+';
    private const byte PlusByte = (byte)Plus;
    private const char Slash = '/';
    private const char Underscore = '_';
    private const int Base64LengthWithoutEquals = 22;

    public static string EncodeBase64String(this Guid guid)
    {
        Span<byte> guidBytes = stackalloc byte[16];
        Span<byte> encodedBytes = stackalloc byte[24];

        MemoryMarshal.TryWrite(guidBytes, ref guid);
        Base64.EncodeToUtf8(guidBytes, encodedBytes, out _, out _);

        Span<char> chars = stackalloc char[Base64LengthWithoutEquals];

        // Replace any characters which are not URL safe.
        // And skip the final two bytes as these will be '==' padding we don't need.
        for (int i = 0; i < Base64LengthWithoutEquals; i++)
        {
            chars[i] = encodedBytes[i] switch
            {
                ForwardSlashByte => Dash,
                PlusByte => Underscore,
                _ => (char)encodedBytes[i],
            };
        }

        return new(chars);
    }

    public static Guid DecodeBase64String(this ReadOnlySpan<char> id)
    {
        Span<char> base64Chars = stackalloc char[24];

        for (var i = 0; i < Base64LengthWithoutEquals; i++)
        {
            base64Chars[i] = id[i] switch
            {
                Dash => Slash,
                Underscore => Plus,
                _ => id[i],
            };
        }

        base64Chars[22] = EqualsChar;
        base64Chars[23] = EqualsChar;

        Span<byte> idBytes = stackalloc byte[16];
        Convert.TryFromBase64Chars(base64Chars, idBytes, out _);

        return new(idBytes);
    }
}
using AutoFixture.Xunit2;
using FluentAssertions;
using Extensions;
using Xunit;

namespace ExtensionTests;

public class GuidExtensionsTests
{
    private const int Base64LengthWithoutEquals = 22;
    private const string EmptyBase64 = "AAAAAAAAAAAAAAAAAAAAAA";

    [Theory]
    [AutoData]
    public void EncodeBase64String_DecodeBase64String_Should_ReturnInitialGuid(Guid guid)
    {
        string actualBase64 = guid.EncodeBase64String();
        actualBase64.Should().NotBe(string.Empty)
            .And.HaveLength(Base64LengthWithoutEquals);

        Guid actualGuid = ((ReadOnlySpan<char>)actualBase64).DecodeBase64String();
        actualGuid.Should().Be(guid);
    }

    [Theory]
    [InlineData(EmptyBase64)]
    public void EncodeBase64String_Should_ReturnEmptyBase64_When_GuidIsEmpty(string expected)
    {
        string actualBase64 = Guid.Empty.EncodeBase64String();
        actualBase64.Should().Be(expected);
    }

    [Theory]
    [InlineData(EmptyBase64)]
    public void DecodeBase64String_Should_ReturnEmptyGuid_When_StringIsEmptyBase64(string base64)
    {
        Guid actual = ((ReadOnlySpan<char>)base64).DecodeBase64String();
        actual.Should().Be(Guid.Empty);
    }
}

For more info read about using high-performance techniques to base64 encode a guid, and a very nice video explanation.

巷雨优美回忆 2024-08-01 16:41:16

如果您的方法无法将传递给它的 Base64 转换为 GUID,您不应该抛出异常吗? 传递给该方法的数据显然是错误的。

If your method cannot convert the Base64 passed to it to a GUID, shouldn't you throw an exception? The data passed to the method is clearly erronous.

孤千羽 2024-08-01 16:41:16

我正在使用一种方法来编码和缩短我的 URL(Guid): https://dotnetfiddle.net /iQ7nGv

public static void Main()
{
    Guid gg = Guid.NewGuid();
    string ss = Encode(gg);
    Console.WriteLine(gg);
    Console.WriteLine(ss);
    Console.WriteLine(Decode(ss));
}

public static string Encode(Guid guid)
{
    string encoded = Convert.ToBase64String(guid.ToByteArray());
    encoded = encoded.Replace("/", "_").Replace("+", "-");
    return encoded.Substring(0, 22);
}

public static Guid Decode(string value)
{
    value = value.Replace("_", "/").Replace("-", "+");
    byte[] buffer = Convert.FromBase64String(value + "==");
    return new Guid(buffer);
}

There is a method that I am using to encode as well as shorten for my URL (Guid): https://dotnetfiddle.net/iQ7nGv

public static void Main()
{
    Guid gg = Guid.NewGuid();
    string ss = Encode(gg);
    Console.WriteLine(gg);
    Console.WriteLine(ss);
    Console.WriteLine(Decode(ss));
}

public static string Encode(Guid guid)
{
    string encoded = Convert.ToBase64String(guid.ToByteArray());
    encoded = encoded.Replace("/", "_").Replace("+", "-");
    return encoded.Substring(0, 22);
}

public static Guid Decode(string value)
{
    value = value.Replace("_", "/").Replace("-", "+");
    byte[] buffer = Convert.FromBase64String(value + "==");
    return new Guid(buffer);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文