You may use an anchored regex with named repeated capturing groups:
\A{(?<val>[^;]*)(?:;(?<val>[^;]*))+}\z
See the regex demo
\A
- start of string
{
- a {
(?<val>[^;]*)
- Group "val" capturing 0+ (due to *
quantifier, if the value cannot be empty, use +
) chars other than ;
(?:;(?<val>[^;]*))+
- 1 or more occurrences (thus, requiring at least 2 values inside {...}
) of the sequence:
;
- a semi-colon
(?<val>[^;]*)
- Group "val" capturing 0+ chars other than ;
}
- a literal }
\z
- end of string.
.NET regex keeps each capture in a CaptureCollection stack, that is why all the values captured into "num" group can be accessed after a match is found.
C# demo:
var s = "{token1;token2;token3;...;tokenn}";
var pat = @"\A{(?<val>[^;]*)(?:;(?<val>[^;]*))+}\z";
var caps = new List<string>();
var result = Regex.Match(s, pat);
if (result.Success)
{
caps = result.Groups["val"].Captures.Cast<Capture>().Select(t=>t.Value).ToList();
}