给定以下字符串(忽略双引号):
"I101G2.2 OZ 001 0002200 L Y 0010000 "
我需要找到每个子字符串的起始位置和长度。例如,使用上面的字符串,第一个子字符串是I101G2.2从位置0开始,长度为8个字符。请记住,每个空格字符(")应被视为子字符串,长度始终为一个字符。因此,输出应该像这样:
**Sub-String Value**,**Starting Position**, **Length**
I101G2.2,0,8
{space},9,1
OZ,10,2
{space},12,1
{space},13,1
001,14,3
{space},17,1
0002200,18,7
{space},25,1
L,26,1
{space},27,1
{space},28,1
{space},29,1
{space},30,1
{space},31,1
{space},32,1
{space},33,1
{space},34,1
Y,35,1
{space},36,1
{space},37,1
{space},38,1
{space},39,1
{space},40,1
{space},41,1
{space},42,1
{space},43,1
0010000,44,7
等等……
我们有一个用Cobol编写的生产系统,它以上述字符串格式输出信息。我有一个表,它将位置和字符串长度映射到另一个表中的列。因此,我们的想法是获取字符串的位置和长度,并与映射表进行比较,以确定该字符串属于哪个表列。例如0002200是项目类,因为它位于位置18,长度为7个字符。
提前感谢!
我很佩服你还能用Cobol运行,我妈妈以前用Cobol写东西…在80年代!
这是我的尝试(它处理所有的空格,甚至那些在字符串的末尾):
IF object_id('tempdb..#t') IS NOT NULL
DROP TABLE #t
GO
CREATE TABLE #t (str VARCHAR(100))
INSERT INTO #t
VALUES ('I101G2.2 OZ 001 0002200 L Y 0010000')
;WITH cte AS(
SELECT cast(CASE WHEN charindex(' ', t.str) = 1 THEN ' ' ELSE LEFT(str, charindex(' ', str)) END AS varchar(100)) str
, 0 AS startPosition
, CASE WHEN charindex(' ', t.str) = 1 THEN 1 ELSE charindex(' ', t.str) END AS nextIndex
, stuff(str, 1,charindex(' ', t.str)-1, '') AS strLeft
FROM #t t
--
UNION ALL
SELECT cast(CASE WHEN charindex(' ', t.strLeft) = 1 THEN ' ' WHEN charindex(' ', t.strleft) = 0 THEN strLeft ELSE LEFT(strLeft, charindex(' ', strLeft)) END AS varchar(100))
, startPosition + nextIndex
, CASE WHEN charindex(' ', t.strLeft) = 1 THEN 1 ELSE charindex(' ', t.strLeft) END
, stuff(strLeft, 1,charindex(' ', t.strLeft) + CASE WHEN charindex(' ', t.strleft) <> 1 THEN -1 ELSE 0 END, '')
FROM CTE t
WHERE datalength(strLeft) > 0
)
SELECT str, startPosition, datalength(str) AS length
FROM cte
OPTION(maxrecursion 0);
要在c#中做到这一点,您可以简单地在循环中遍历字符串。当我们遇到非空格字符时,我们可以将它们附加到StringBuilder
。当我们遇到空格时,我们将首先添加到目前为止捕获的字符,以及它们的长度和起始位置,到字符串列表中(每个字符串代表一个子字符串),清除下一个子字符串的StringBuilder
,然后添加空格字符及其位置和长度。在循环结束时,如果StringBuilder
中有子字符串,则将其添加到列表中,然后返回列表。
原始示例中的一个错误是第一个子字符串从位置0
开始,并且具有8
字符。这意味着下一个子字符串应该从位置8
开始,但您的示例显示它从位置9
开始。
有一种方法:
public static List<string> GetParts(string input)
{
if (input == null) return null;
var result = new List<string>();
if (input.Length == 0) return result;
var currentPart = new StringBuilder();
for (int i = 0; i < input.Length; i++)
{
if (input[i] == ' ')
{
if (currentPart.Length > 0)
{
var part = currentPart.ToString();
result.Add($"{part},{i - part.Length},{part.Length}");
currentPart.Clear();
}
result.Add($"{{space}},{i},1");
}
else
{
currentPart.Append(input[i]);
}
}
if (currentPart.Length > 0)
{
var part = currentPart.ToString();
result.Add($"{part},{input.Length - part.Length - 1},{part.Length}");
}
return result;
}
和一个叫做
的例子static void Main(string[] args)
{
var input =
"I101G2.2 OZ 001 0002200 L Y 0010000 ";
var parts = GetParts(input);
parts.ForEach(Console.WriteLine);
Console.Write("nnDone. Press any key to exit...");
Console.ReadKey();
}
我不确定您在这里的确切要求,但这是一个非常标准的字符串分割与序数类型的情况。
试一下:
SET ANSI_PADDING ON
DECLARE @ThatsALongOne NVARCHAR(MAX) = 'I101G2.2 OZ 001 0002200 L Y 0010000 ';
DECLARE @WhaddaYaWant NVARCHAR(10) = ' ';
SET @ThatsALongOne+='.'
;WITH cte AS
(
SELECT @ThatsALongOne AS TheWholeSheBang,
CHARINDEX(@WhaddaYaWant,@ThatsALongOne)-1 AS CI, LEN(@ThatsALongOne) AS LEN,
CASE WHEN LEFT(LEFT(@ThatsALongOne ,CHARINDEX(@WhaddaYaWant,@ThatsALongOne)),1) = @WhaddaYaWant THEN @WhaddaYaWant ELSE LEFT(@ThatsALongOne ,CHARINDEX(@WhaddaYaWant,@ThatsALongOne)) END AS This,
CASE WHEN LEFT(LEFT(@ThatsALongOne ,CHARINDEX(@WhaddaYaWant,@ThatsALongOne)),1) = @WhaddaYaWant THEN RIGHT(@ThatsALongOne, LEN(@ThatsALongOne) -CHARINDEX(@WhaddaYaWant,@ThatsALongOne )) ELSE RIGHT(@ThatsALongOne, 1+ LEN(@ThatsALongOne) -CHARINDEX(@WhaddaYaWant,@ThatsALongOne )) END AS WhatsLeft
, 1 AS Incidence
, CAST(0 AS BIGINT) AS Start
UNION ALL
SELECT @ThatsALongOne AS TheWholeSheBang,
CASE WHEN LEFT(LEFT(WhatsLeft ,CHARINDEX(@WhaddaYaWant,WhatsLeft)),1) = @WhaddaYaWant THEN 1 ELSE LEN(LEFT(WhatsLeft ,CHARINDEX(@WhaddaYaWant,WhatsLeft))) END AS CI,
LEN(WhatsLeft) AS LEN,
CASE WHEN LEFT(LEFT(WhatsLeft ,CHARINDEX(@WhaddaYaWant,WhatsLeft)),1) = @WhaddaYaWant THEN @WhaddaYaWant ELSE LEFT(WhatsLeft ,CHARINDEX(@WhaddaYaWant,WhatsLeft)) END AS This,
CASE WHEN LEFT(LEFT(WhatsLeft ,CHARINDEX(@WhaddaYaWant,WhatsLeft)),1) = @WhaddaYaWant THEN RIGHT(@ThatsALongOne, LEN(WhatsLeft) -CHARINDEX(@WhaddaYaWant,WhatsLeft )) ELSE RIGHT(WhatsLeft, 1+ LEN(WhatsLeft) -CHARINDEX(@WhaddaYaWant,WhatsLeft )) END AS WhatsLeft
, Incidence + 1 AS Incidence
, CASE WHEN LEFT(LEFT(WhatsLeft ,CHARINDEX(@WhaddaYaWant,WhatsLeft)),1) = @WhaddaYaWant THEN 1 ELSE CHARINDEX(@WhaddaYaWant,WhatsLeft) END
FROM cte
WHERE WhatsLeft <> '.'
)
SELECT This AS SubString, SUM(CI) OVER (PARTITION BY cte.TheWholeSheBang ORDER BY cte.Incidence)-CI AS StartingPosition, CI AS Length
FROM cte
SubString StartingPosition Length
I101G2.2 0 8
8 1
OZ 9 2
11 1
12 1
001 13 3
..