是否有任何(C#中的)方式(在C#中)将字符串转换为较小的字符串,当我说较小时,我的意思是“长度缩小&quot”?
让我解释一下:在我的用例中,系统会给我许多字符串,这些字符串的大小可能会有所不同(字符数;长度),有时可能真的很大!问题是我必须将此字符串保存在“ SQL Server”数据库表的列中,坏消息是我不允许在此数据库中进行任何迁移,好消息是该列已经已经具有键入nvarchar(max)
。
我以前做过一些研究,并遵循以下帖子,使用“ Gzip”和“ Brotli”编写数据压缩机。
https://khalidabuhakmeh.com/khalidabuhakmeh.com/ csharp
var value = "hello world";
var level = CompressionLevel.SmallestSize;
var bytes = Encoding.Unicode.GetBytes(value);
await using var input = new MemoryStream(bytes);
await using var output = new MemoryStream();
// GZipStream with BrotliStream
await using var stream = new GZipStream(output, level);
await input.CopyToAsync(stream);
var result = output.ToArray();
var resultString = Convert.ToBase64String(result);
实施转换方法后,我创建了测试,以生成不同尺寸(长度)的随机字符串以验证压缩机的性能,此时,我注意到了以下内容。 “ gzip”和“ brotli”首先转换为字节[](字节数组),然后应用压缩,该压缩将结果向量向量(字节阵列)缩小尺寸,然后将结果(字节[])转换为一个基本64字符串,在100%测试中,它具有比初始字符串更多的字符(长度)。
我的随机字符串生成器:
var rd_char = new Random();
var rd_length = new Random();
var wordLength = rd_length.Next(randomWordParameters.WordMinLength, randomWordParameters.WordMaxLength);
var sb = new StringBuilder();
int sourceNumber;
for (int i = 0; i < wordLength; i++)
{
sourceNumber = rd_char.Next(randomWordParameters.CharLowerBound, randomWordParameters.CharUpperBound);
sb.Append(Convert.ToChar(sourceNumber));
}
var word = sb.ToString();
我的示例字符串并不完全包含手头案件的完美表示,但我相信它们足够好。这是字符串生成器方法,实际上它在给定的尺寸范围内生成了完全随机的字符串,我在传递给convert.tochar()方法的33〜127值提供的测试字符中使用。系统提供的字符串是JSON格式的,实际上它们是URL列表(具有数万个URL),URL通常具有随机的字符序列,因此我试图生成尽可能随机的字符串。
事实是,考虑到我试图将最初(压缩之前)的字符串保存在数据库中的情况,该字符串大于列中允许的最大尺寸(长度),当保存在数据库中时,即将进行的“数据”在所讨论的表的列中是结果“基本64”字符串在压缩后生成的,而不是缩小的大小向量(字节数组),我相信数据库将拒绝字符串(基本64),因为它的长度(数字为数字)字符)大于原始字符串的长度。
因此,这是我的问题,是否有任何(可逆的)将字符串转换为较小的方法,当我说较小时,我的意思是“长度减少”?似乎“ Gzip”或“ Brotli”并不能解决问题。
PS:我确保多次强调“长度”一词,以明确说明在文本中,我在谈论字符的数量,而不是记忆中的长度,因为我在几个论坛中注意到了我阅读的几个论坛以前,这种混乱使得很难得出结论。
Let me explain: in my use case a system gives me many strings that can vary in size (number of characters; length), sometimes it can be really huge! The problem is that I have to save this string in a column of a table of a "SQL Server" database, the bad news is that I am not allowed to do any migration in this database, the good news is that the column already has type nvarchar(max)
.
I've done some research before and followed the following post to write a data compressor using "Gzip" and "Brotli".
https://khalidabuhakmeh.com/compress-strings-with-dotnet-and-csharp
var value = "hello world";
var level = CompressionLevel.SmallestSize;
var bytes = Encoding.Unicode.GetBytes(value);
await using var input = new MemoryStream(bytes);
await using var output = new MemoryStream();
// GZipStream with BrotliStream
await using var stream = new GZipStream(output, level);
await input.CopyToAsync(stream);
var result = output.ToArray();
var resultString = Convert.ToBase64String(result);
After implementing the conversion methods, I created tests that generate random strings of varying sizes (length) to validate the performance of the compressors, at this point I noticed the following. Both "Gzip" and "Brotli" first convert to byte[] (byte array), then apply compression, which gives a result vector (byte array) of reduced size as expected, but then converts the result (byte[]) to a base 64 string that, in 100% of the tests it has more characters (length) than the initial string.
My random string generator:
var rd_char = new Random();
var rd_length = new Random();
var wordLength = rd_length.Next(randomWordParameters.WordMinLength, randomWordParameters.WordMaxLength);
var sb = new StringBuilder();
int sourceNumber;
for (int i = 0; i < wordLength; i++)
{
sourceNumber = rd_char.Next(randomWordParameters.CharLowerBound, randomWordParameters.CharUpperBound);
sb.Append(Convert.ToChar(sourceNumber));
}
var word = sb.ToString();
My sample strings don't exactly contain perfect representations of the cases at hand, but I believe they are good enough. Here's the string generator method, in fact it generates completely random strings in a given size range, and I used in the tests characters provided from the 33 ~ 127 values passed to the Convert.ToChar() method. The strings provided by the system are in JSON format, in practice they are lists of URLs (with tens of thousands of urls), the urls usually have random sequences of characters, so I tried to generate strings as random as possible.
The fact is that, considering the case where I try to save in the database a string that originally (before compression) is larger than the maximum size (length) allowed in the column, when saving in the database, the "data" that goes to the column of the table in question is the result "base 64" string generated after compression and not the reduced size vector (byte array), and I believe the database will refuse the string (base 64) since its length (in the number of characters) is greater than the length of the original string.
So here's my question, is there any (invertible) way to convert a string into a smaller one, and when I say smaller I mean "with reduced length"? It seems that "Gzip" or "Brotli" doesn't solve the problem.
PS: I made sure to highlight the term "length" several times to make it clear that at that point in the text I'm talking about the number of characters and not the length in memory, because I noticed in several forums that I read before, that this confusion was making it difficult to reach conclusions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
压缩算法正在利用输入流中的重复模式。典型的URL中没有太多的重复,因此压缩单个URL不太可能产生比原始URL短得多的表示形式。如果URL根本没有重复模式(如果接近随机字符串),则压缩算法将产生比输入更大的输出。
以下是这种行为的证明,使用 <代码> encoding.utf8 将URL转换为字节,
encoding.latin1
将压缩字节转换为字符串:我使用了三个相当长且非重复的URL进行测试:
输出:output:
在小提琴上尝试一下。
压缩后,三个URL中的两个略短,但第三个URL却肿了。
您可以将压缩值或原始值存储在数据库中,具体取决于较短的值。您可以将存储的值带有一些标记,例如
'C'
或'u'
,以便您知道它是压缩还是未压缩。The compression algorithms are exploiting repetitive patterns in the input stream. There is no much repetition in a typical URL, so compressing a single URL is unlikely to yield a representation that is much shorter than the original. In case the URL has no repetitive patterns at all (if it's close to a random string), the compression algorithm is going to yield a larger output than the input.
Below is a demonstration of this behavior, using the
Encoding.UTF8
to convert the URLs to bytes, and theEncoding.Latin1
to convert the compressed bytes to a string:I used three fairly long and non-repetitive URLs for the test:
Output:
Try it on Fiddle.
Two of the three URLs became slightly shorter after the compression, but the third URL was bloated instead.
You could store in the database either the compressed or the original value, depending on which is the shorter one. You could prefix the stored value with some marker, for example
'C'
or'U'
, so that you know if it's compressed or uncompressed.NVARCHAR类型(MAX)类型的最大尺寸为2 Gbyte。
由于NVarchar使用每个字符2个字节,因此大约是。十亿个字符。
因此,我认为您实际上不需要进行压缩,如果问题是检索数据时的性能,那么您可以使用服务器端缓存系统。
The max size for a column of type NVARCHAR(MAX) is 2 GByte of storage.
Since NVARCHAR uses 2 bytes per character, that's approx. 1 billion characters.
So I don't think you actually need to make a compression, if the problem is the performance when retrieving data, then you can use a server side caching system.