Serialization C#&;T-SQL字符串[]打包/解包实用程序函数
熟悉t-sql的任何人都可以为这些C#数组打包和解包实用程序方法创建表值函数,这些方法通过往返编码转义分隔符并保留空数组、空数组和空数组吗 通过将任何种类的字符串数组打包到一个字符串中,您可以将这些(小)数组作为参数传递给SQL,这在某些情况下非常有用Serialization C#&;T-SQL字符串[]打包/解包实用程序函数,serialization,Serialization,熟悉t-sql的任何人都可以为这些C#数组打包和解包实用程序方法创建表值函数,这些方法通过往返编码转义分隔符并保留空数组、空数组和空数组吗 通过将任何种类的字符串数组打包到一个字符串中,您可以将这些(小)数组作为参数传递给SQL,这在某些情况下非常有用 static class ArrayUtil { public static string Pack(string[] original) { return Pack(original, '|', '0', '~'
static class ArrayUtil
{
public static string Pack(string[] original)
{
return Pack(original, '|', '0', '~');
}
public static string[] Unpack(string original)
{
return Unpack(original, '|', '0', '~');
}
public static string Pack(string[] original, char delimiter, char zed, char escape)
{
if (delimiter == escape ||
zed == escape ||
delimiter == zed) throw new ArgumentException("special characters must be distinct");
// Null array returns a null string
if (original == null) return null;
// Empty array returns an empty string
if (original.Length == 0) return string.Empty;
// Arrays with a single empty element are represented as just the escape character
// to differentiate from an empty array
if (original.Length == 1 && original[0] == string.Empty) return escape.ToString();
// Otherwise
StringBuilder sb = new StringBuilder();
for (int i = 0, ol = original.Length; i < ol; i++)
{
string s = original[i];
if (s == null)
{
sb.Append(zed); // zed == null
}
else
{
for (int j = 0, sl = s.Length; j < sl; j++)
{
char c = s[j];
// escape literal delimiters, escapes, and leading zeds
if (c == delimiter ||
c == escape ||
(c == zed && j == 0)) sb.Append(escape);
sb.Append(c);
}
}
if (i != ol - 1) sb.Append(delimiter); // no trailing delimiter
}
return sb.ToString();
}
public static string[] Unpack(string original, char delimiter, char zed, char escape)
{
if (delimiter == escape ||
zed == escape ||
delimiter == zed) throw new ArgumentException("special characters must be distinct");
// Null string returns a null array
if (original == null) return null;
// Empty string returns an empty array
if (original == string.Empty) return new string[] { };
// A single escape character represents an array with a single empty element
// to differentiate from an empty array
if (original == escape.ToString()) return new string[] { string.Empty };
// Otherwise
StringBuilder sb = new StringBuilder(); // A place to store the current element
StringReader sr = new StringReader(original); // A stream of the original string
List<string> unpacked = new List<string>(); // The finished elements
int next;
while ((next = sr.Read()) >= 0)
{
char c = (char)next;
if (c == zed && sb.Length == 0)
{
unpacked.Add(null);
if ((next = sr.Peek()) >= 0 && (char)next != delimiter)
throw new ArgumentException("An element's leading zed character must be escaped or must alone be the element", "original");
sb = null;
}
else if (c == delimiter)
{
if (sb != null) unpacked.Add(sb.ToString());
sb = new StringBuilder();
}
else if (c == escape)
{
if ((next = sr.Read()) >= 0)
{
sb.Append((char)next);
}
else
throw new ArgumentException("Escapee expected", "original");
}
else
{
sb.Append(c);
}
}
// A final zed character will make sb = null, but otherwise we have an additional element
if (sb != null) unpacked.Add(sb.ToString());
return unpacked.ToArray();
}
}
一些特殊情况(由PEX发现)
下面是T-SQL解包的一个尝试:
CREATE FUNCTION [dbo].[UnpackStrings]
(
@original nvarchar(4000),
@delimiter nchar(1),
@zed nchar(1),
@escape nchar(1)
)
RETURNS
@unpacked TABLE
(
elementNumber INT IDENTITY(1,1),
element nvarchar(4000)
)
AS
BEGIN
DECLARE @next int;
DECLARE @c nchar(1);
DECLARE @pos int;
DECLARE @sb nvarchar(4000);
-- Special characters must be distinct.
IF ( (@delimiter = @escape) OR
(@zed = @escape) OR
(@delimiter = @zed) )
RETURN;
-- Null string return a null array
IF (@original IS NULL)
RETURN;
-- A single escape character represents an array with a single
-- empty element to differentiate from an empty array.
IF (@original = @escape)
BEGIN
INSERT @unpacked (element) VALUES ('');
RETURN;
END
-- Otherwise read through the string and unpack.
SET @pos = 1;
SET @sb = '';
SET @next = 0;
-- Fill the table variable with the rows for your result set
WHILE( (@pos <= LEN(@original)) AND @next IS NOT NULL )
BEGIN
SET @next = UNICODE(SUBSTRING(@original, @pos, 1));
IF (@next IS NULL)
BEGIN
IF (LEN(@sb) > 0)
INSERT @unpacked (element) VALUES (@sb);
SET @sb = '';
CONTINUE;
END
ELSE
BEGIN
SET @c = NCHAR(@next);
IF ( @c = @zed AND (LEN(@sb) = 0 OR LEN(@sb) IS NULL) )
BEGIN
INSERT @unpacked (element) VALUES (NULL);
-- need to peek at next character,
SET @next = UNICODE(SUBSTRING(@original, @pos+1, 1));
IF (@next IS NOT NULL)
BEGIN
SET @c = NCHAR(@next);
IF ( @c != @delimiter )
BEGIN
-- Peek at next character and it not delimiter,
-- bad format encountered.
BREAK;
END
END
SET @sb = NULL;
END
ELSE
BEGIN
IF ( @c = @delimiter )
BEGIN
IF (LEN(@sb) > 0 )
INSERT @unpacked (element) VALUES (@sb);
SET @sb = '';
END
ELSE
BEGIN
IF ( @c = @escape )
BEGIN
SET @pos = @pos + 1;
SET @next = UNICODE(SUBSTRING(@original, @pos, 1));
IF (@next IS NULL )
BEGIN
CONTINUE;
END
ELSE
BEGIN
SET @sb = @sb + NCHAR(@next);
END
END
ELSE
BEGIN
SET @sb = @sb + @c;
END
END
END
--
END
SET @pos = @pos + 1;
END
--
-- Likely not needed. This is handled above.
--
-- A final zed character will made sb = null,
-- but otherwise we have an additional element.
IF (@sb IS NOT NULL )
INSERT @unpacked (element) VALUES (@sb);
RETURN
END
CREATE函数[dbo].[unpack字符串]
(
@原始nvarchar(4000),
@分隔符nchar(1),
@zed nchar(1),
@逃逸中心(1)
)
返回
@未打包的桌子
(
元素编号整数标识(1,1),
元素nvarchar(4000)
)
作为
开始
声明@next int;
声明@c nchar(1);
声明@pos int;
宣布@sb nvarchar(4000);
--特殊字符必须是不同的。
如果(@delimiter=@escape)或
(@zed=@escape)或
(@delimiter=@zed))
返回;
--空字符串返回空数组
如果(@original为空)
返回;
--单个转义字符表示具有单个
--空元素以区别于空数组。
如果(@original=@escape)
开始
插入@未包装(元素)值(“”);
返回;
结束
--否则,请通读字符串并解压缩。
设置@pos=1;
设置@sb='';
设置@next=0;
--用结果集的行填充表变量
而(@pos 0)
插入@unpacket(元素)值(@sb);
设置@sb='';
继续;
结束
其他的
开始
设置@c=NCHAR(@next);
如果(@c=@zed和(LEN(@sb)=0或LEN(@sb)为空))
开始
插入@unpacket(元素)值(NULL);
--需要偷看下一个角色,
设置@next=UNICODE(子字符串(@original,@pos+1,1));
IF(@next不为空)
开始
设置@c=NCHAR(@next);
IF(@c!=@分隔符)
开始
--看下一个字符,它不是分隔符,
--遇到错误的格式。
打破
结束
结束
设置@sb=NULL;
结束
其他的
开始
IF(@c=@delimiter)
开始
如果(LEN(@sb)>0)
插入@unpacket(元素)值(@sb);
设置@sb='';
结束
其他的
开始
IF(@c=@escape)
开始
设置@pos=@pos+1;
设置@next=UNICODE(子字符串(@original,@pos,1));
如果(@next为空)
开始
继续;
结束
其他的
开始
设置@sb=@sb+NCHAR(@next);
结束
结束
其他的
开始
设置@sb=@sb+@c;
结束
结束
结束
--
结束
设置@pos=@pos+1;
结束
--
--可能不需要。这在上面处理。
--
--最后一个zed字符将使sb=null,
--但除此之外,我们还有一个额外的因素。
如果(@sb不为空)
插入@unpacket(元素)值(@sb);
返回
结束
这是一个小错误。这里更新了GIST:,并改进了C#
null -> null
[null] -> "0"
[null, null] -> "0|0"
[] -> ""
[""] -> "~"
["", ""] -> "|"
["|", "|"] -> "~||~|"
CREATE FUNCTION [dbo].[UnpackStrings]
(
@original nvarchar(4000),
@delimiter nchar(1),
@zed nchar(1),
@escape nchar(1)
)
RETURNS
@unpacked TABLE
(
elementNumber INT IDENTITY(1,1),
element nvarchar(4000)
)
AS
BEGIN
DECLARE @next int;
DECLARE @c nchar(1);
DECLARE @pos int;
DECLARE @sb nvarchar(4000);
-- Special characters must be distinct.
IF ( (@delimiter = @escape) OR
(@zed = @escape) OR
(@delimiter = @zed) )
RETURN;
-- Null string return a null array
IF (@original IS NULL)
RETURN;
-- A single escape character represents an array with a single
-- empty element to differentiate from an empty array.
IF (@original = @escape)
BEGIN
INSERT @unpacked (element) VALUES ('');
RETURN;
END
-- Otherwise read through the string and unpack.
SET @pos = 1;
SET @sb = '';
SET @next = 0;
-- Fill the table variable with the rows for your result set
WHILE( (@pos <= LEN(@original)) AND @next IS NOT NULL )
BEGIN
SET @next = UNICODE(SUBSTRING(@original, @pos, 1));
IF (@next IS NULL)
BEGIN
IF (LEN(@sb) > 0)
INSERT @unpacked (element) VALUES (@sb);
SET @sb = '';
CONTINUE;
END
ELSE
BEGIN
SET @c = NCHAR(@next);
IF ( @c = @zed AND (LEN(@sb) = 0 OR LEN(@sb) IS NULL) )
BEGIN
INSERT @unpacked (element) VALUES (NULL);
-- need to peek at next character,
SET @next = UNICODE(SUBSTRING(@original, @pos+1, 1));
IF (@next IS NOT NULL)
BEGIN
SET @c = NCHAR(@next);
IF ( @c != @delimiter )
BEGIN
-- Peek at next character and it not delimiter,
-- bad format encountered.
BREAK;
END
END
SET @sb = NULL;
END
ELSE
BEGIN
IF ( @c = @delimiter )
BEGIN
IF (LEN(@sb) > 0 )
INSERT @unpacked (element) VALUES (@sb);
SET @sb = '';
END
ELSE
BEGIN
IF ( @c = @escape )
BEGIN
SET @pos = @pos + 1;
SET @next = UNICODE(SUBSTRING(@original, @pos, 1));
IF (@next IS NULL )
BEGIN
CONTINUE;
END
ELSE
BEGIN
SET @sb = @sb + NCHAR(@next);
END
END
ELSE
BEGIN
SET @sb = @sb + @c;
END
END
END
--
END
SET @pos = @pos + 1;
END
--
-- Likely not needed. This is handled above.
--
-- A final zed character will made sb = null,
-- but otherwise we have an additional element.
IF (@sb IS NOT NULL )
INSERT @unpacked (element) VALUES (@sb);
RETURN
END