C# 如何在较大的字符串中找到多个子字符串中的一个?

C# 如何在较大的字符串中找到多个子字符串中的一个?,c#,split,C#,Split,我有一个简单的问题,但我还没有找到一个简单的解决办法 我有一个字符串,其中包含例如这个 UNB+123UNH+234BGM+345DTM+456 实际的字符串要大得多,但你明白了 现在我需要在这个字符串中找到一组值 例如UNH和BGM和DTM等等 因此,我需要在大字符串中搜索,并找到第一组值的位置。 类似这样的东西(不存在,但用于解释想法) 在这种情况下,pos将是8,因为在所有3个子字符串中,UNH是变量test 实际上,我试图实现的是将大字符串拆分为字符串列表,但分隔符可以是许多值(“BGM

我有一个简单的问题,但我还没有找到一个简单的解决办法

我有一个字符串,其中包含例如这个
UNB+123UNH+234BGM+345DTM+456

实际的字符串要大得多,但你明白了

现在我需要在这个字符串中找到一组值
例如
UNH
BGM
DTM
等等

因此,我需要在大字符串中搜索,并找到第一组值的位置。
类似这样的东西(不存在,但用于解释想法)

在这种情况下,
pos
将是8,因为在所有3个子字符串中,
UNH
是变量
test

实际上,我试图实现的是将大字符串拆分为字符串列表,但分隔符可以是许多值(“BGM”、“UNH”、“DTM”)中的一个
所以结果是

UNB+123
UNH+234
BGM+345
DTM+456
我当然可以构建一个循环,对每个子字符串执行
IndexOf
,然后记住最小的值,但这似乎效率很低。我希望有一个更好的方法来做到这一点

编辑
要搜索的子字符串始终为3个字母,但中间的文本可以是任何长度的任何内容

编辑

它总是3个数字字符,然后任何东西都可以在那里,还有许多+符号

您会发现EDI的问题不仅仅是拆分成相应的字段,还有条件、多个值或列表呢?。我建议你去看看

编辑:
EDIFact
是一种非常复杂的格式,只需使用regex,正如我前面提到的,每个格式/字段/进程都有条件,需要捕获整个字段才能真正解析它,例如,意味着DTM可以具有一种特定的日期时间格式,而在另一种EDI中,可以具有完全不同的
datetime
格式

但是,这是
DTM
字段的结构:

    DTM  DATE/TIME/PERIOD


       Function: To specify date, and/or time, or period.

010    C507 DATE/TIME/PERIOD                           M    1
       2005  Date or time or period function code
             qualifier                                 M      an..3
       2380  Date or time or period text               C      an..35
       2379  Date or time or period format code        C      an..3
因此,您将始终可以搜索类似“DTM+d3:d35:d3”的内容

真的,这不值得奋斗,使用EDI.net,创建自己的POCO类,然后从那里开始工作


友好的提醒,Edvices在欧洲每6个月改变一次。

< p>听起来好像其他答案识别了格式——你绝对应该考虑一个专门用于解析这种格式的库。 如果您想自己解析它,只需在字符串中找到标识符的索引,按位置确定前2个,并使用这些位置来
子字符串
原始输入

var input = "UNB+123UNH+234BGM+345DTM+456";
var chars = new[]{"UNH", "BGM", "DTM" };
var indexes = chars.Select(c => new{Length=c.Length,Position= input.IndexOf(c)})  // Get position and length of each input
                 .Where(x => x.Position>-1) // where there is actually a match
                 .OrderBy(x =>x.Position) // put them in order of the position in the input
                 .Take(2) // only interested in first 2
                 .ToArray(); // make it an array
if(indexes.Length < 2)
    throw new Exception("Did not find 2");   

var result = input.Substring(indexes[0].Position + indexes[0].Length, indexes[1].Position - indexes[0].Position - indexes[0].Length);
var input=“UNB+123UNH+234BGM+345DTM+456”;
var chars=new[]{“UNH”、“BGM”、“DTM”};
var index=chars.Select(c=>new{Length=c.Length,Position=input.IndexOf(c)})//获取每个输入的位置和长度
.Where(x=>x.Position>-1)//实际存在匹配的位置
.OrderBy(x=>x.Position)//将它们按输入中的位置顺序排列
.Take(2)//只对前2个感兴趣
.ToArray();//让它成为一个数组
如果(索引长度<2)
抛出新异常(“未找到2”);
var result=input.Substring(索引[0]。位置+索引[0]。长度,索引[1]。位置-索引[0]。位置-索引[0]。长度);

实例:

如果分隔符可以是UNB、UNH、BGM或DTM中的任意一个,则以下正则表达式可以工作:

foreach (Match match in Regex.Matches(input, @"(UNB|UNH|BGM|DTM).+?(?=(UNB|UNH|BGM|DTM)|$)"))
{
    Console.WriteLine(match.Value);
}
说明:

  • (UNB | UNH | BGM | DTM)匹配任一分离器
  • .+?使用至少一个字符匹配任何字符串(但尽可能短)
  • (?=(UNB | UNH | BGM | DTM)|$)如果后面有分隔符或字符串结束于此,则匹配-但该匹配不包括在值中

这是一个相当有效的O(n)解决方案,使用
哈希集

它非常简单,低分配,比正则表达式更高效,并且不需要库

给定的

private static HashSet<string> _set;

public static IEnumerable<string> Split(string input)
{
   var last = 0;

   for (int i = 0; i < input.Length-3; i++)
   {
      if (!_set.Contains(input.Substring(i, 3))) continue;
      yield return input.Substring(last, i - last);
      last = i;
   }
   yield return input.Substring(last);
}


注意:使用一个简单的排序树,你可以更快地得到这个结果,但需要更多的努力

这里已经有很多答案了,但我花了时间写了我的答案,所以即使它没有那么优雅,也不妨发布它

代码假定所有标记都在
chars
数组中进行了说明

string str=“UNB+123UNH+234BGM+345DTM+456”;
字符串[]字符={“UNH”、“BGM”、“DTM”};
var locations=chars.Select(o=>str.IndexOf(o)).Where(i=>i>-1.OrderBy(o=>o);
var resultList=新列表();
对于(int i=0;i0?nextIndex:str.Length;
nextIndex=nextIndex-位置。元素位于(i);
结果列表.Add(str.Substring(locations.ElementAt(i),nextIndex));
}

当然,我可以建立一个循环来为每个子串做索引,然后记住最小的值,但是看起来效率太低了。“你有没有对这一点做过判断?它总是<代码> [3个字母] + [ 3个数字] < /代码>?你是否考虑过使用正则表达式?比如“@”(BGM | UNH | DTM)。+?”@Cid不,我没有。在我开始之前,我想在这里问一下这个问题。我说的是50个可能的子字符串,所以这是一个小问题work@AustinG不,它总是以3个字母开头,但是在下一个分隔符之前的文本可以是任何东西。谢谢你的回答,我一定会读这个。但我也需要这个做其他用途EDI@GuidoG您应该更详细地了解为什么EDI-to-POCO解析库不能满足您的需求。@CaiusJard我肯定会阅读这个库,我不知道它的存在。但不幸的是,我还需要这个用于其他目的。肯尼,非常感谢你的评论和链接。我安装了这个软件包,经过一些研究,我能够使用它来读取EDI文件。确实容易多了。内肯尼尔,你似乎对Edi.net有一些了解,你能看看这个问题吗?
private static HashSet<string> _set;

public static IEnumerable<string> Split(string input)
{
   var last = 0;

   for (int i = 0; i < input.Length-3; i++)
   {
      if (!_set.Contains(input.Substring(i, 3))) continue;
      yield return input.Substring(last, i - last);
      last = i;
   }
   yield return input.Substring(last);
}
_set = new HashSet<string>(new []{ "UNH", "BGM", "DTM" });

var results = Split("UNB+123UNH+234BGM+345DTM+456");

foreach (var item in results)
   Console.WriteLine(item);
UNB+123
UNH+234
BGM+345
DTM+456