与多组c#匹配的正则表达式模式



我有一个类似的文件:

background_color{ 104, 184, 104 }
tile_pattern{
id = "1",
ground = "empty",
default_layer = 2,
x = 0,
y = 0,
width = 8,
height = 16,
repeat_mode = "none",
}
tile_pattern{
id = "999",
ground = "traversable",
default_layer = 0,
x = 40,
y = 1000,
width = 8,
height = 8,
}
tile_pattern{
id = "abyss_bridge",
ground = "traversable",
default_layer = 0,
x = 280,
y = 448,
width = 16,
height = 16,
}
tile_pattern{
id = "acid",
ground = "prickles",
default_layer = 0,
x = { 712, 728, 744 },
y = { 384, 384, 384 },
width = 16,
height = 16,
}
tile_pattern{
id = "lava",
ground = "lava",
default_layer = 0,
x = { 696, 696, 696, 696 },
y = { 368, 384, 400, 384 },
width = 16,
height = 16,
}
tile_pattern{
id = "hole_parallax.1-1",
ground = "hole",
default_layer = 0,
x = 312,
y = 224,
width = 16,
height = 16,
scrolling = "self",
}
tile_pattern{
id = "air_duct.1",
ground = "wall",
default_layer = 0,
x = 880,
y = 48,
width = 32,
height = 24,
repeat_mode = "none",
}
border_set{
id = "wall_hole",
inner = true,
pattern_0 = "wall_hole.4-1",
pattern_1 = "wall_hole.1-1",
pattern_2 = "wall_hole.3-1",
pattern_3 = "wall_hole.2-1",
pattern_4 = "wall_hole.corner.2-1",
pattern_5 = "wall_hole.corner.1-1",
pattern_6 = "wall_hole.corner.3-1",
pattern_7 = "wall_hole.corner.4-1",
pattern_8 = "wall_hole.corner_reverse.2-1",
pattern_9 = "wall_hole.corner_reverse.1-1",
pattern_10 = "wall_hole.corner_reverse.3-1",
pattern_11 = "wall_hole.corner_reverse.4-1",
}
border_set{
id = "wall_low-1",
pattern_0 = "wall_low.4-1",
pattern_1 = "wall_low.1-1",
pattern_2 = "wall_low.3-1",
pattern_3 = "wall_low.2-1",
pattern_4 = "wall_low.corner.2-1",
pattern_5 = "wall_low.corner.1-1",
pattern_6 = "wall_low.corner.3-1",
pattern_7 = "wall_low.corner.4-1",
pattern_8 = "wall_low.corner_reverse.2-1b",
pattern_9 = "wall_low.corner_reverse.1-1b",
pattern_10 = "wall_low.corner_reverse.3-1b",
pattern_11 = "wall_low.corner_reverse.4-1b",
}

我把它加载到一个叫做datString的字符串中。我试图在单个正则表达式中匹配所有tile_pattern部分。

这是我目前为止写的:

//tilePatterns = new List<TilePatternData>();
//tile_pattern{
//id = "10", (string)
//ground = "empty", (string)
//default_layer = 2, (number)
//(x = 72,) (x = { 712, 728, 744 },) (number or table)(only matching the number, have to add in the table)
//(y = 0,) (y = { 384, 384, 384 },) (number or table)(only matching the number, have to add in the table)
//width = 8,
//height = 16,
//frame_delay(number, optional)(None in test file)
//mirror_loop (boolean, optional)(None in test file)
//scrolling (string, optional)(The Ones in the test file do not have a repeat_mode
//repeat_mode = "none", (string, optional)
//}
parts = new Regex("tile_pattern\s*{\s*(id\s*=\s*".+",\s*ground\s*=\s*".+",\s*default_layer\s*=\s*-*\d+,\s*x\s*=\s*\d+,\s*y\s*=\s*\d+,\s*width\s*=\s*\d+,\s*height\s*=\s*\d+,\s*\w*\s*=*\s*"*\w*"*),*\s*}");
match = parts.Match(datFileString);
Debug.Log("Match " + match.Success + " : " + match.Length);
while (match.Success)
{
// To easily see which ones are getting loaded in
Debug.Log(match.Groups[1]);
//TilePatternData tilePatternData = new TilePatternData();
//tilePatternData.LoadFromDatFile(match.Groups[1].ToString());
//tilePatterns.Add(tilePatternData);
match = match.NextMatch();
}

返回匹配长度为138(应该是4830),通过我的调试日志一目了然,唯一似乎缺少的是32种模式,x ={712,728,744},我还没有弄清楚如何将其添加到我的捕获组中,但任何帮助都将受到赞赏。此外,我如何添加3个可选字段,以确保如果他们都在那里,他们会得到匹配?

需要添加到模式

tile_pattern{
id = "acid",
ground = "prickles",
default_layer = 0,
x = { 712, 728, 744 },
y = { 384, 384, 384 },
width = 16,
height = 16,
}

您的文件输入似乎来自Solarus Quest Tileset数据文件。根据规格:

tileset数据文件的语法实际上是有效的Lua。

考虑使用Lua解析器,而不是使用Regex。NLua似乎可以用Lua做很多事情,尽管它可能只是解析变量列表表示法有点多。

参见:在c#/.Net中解析Lua数据结构的最简单方法

你的正则表达式真的比它要复杂得多…现在只有你和上帝知道它的作用——一周后只有上帝知道;-)

试试这个regex:tile_pattern{(?:[^{}]|(?R))+}

请确保设置正确的标志(因为我不知道c#语法)

  • global(第一次匹配后不返回)
  • 扩展(忽略空白)

也可参考此示例https://regex101.com/r/zqcOBY/1

这还负责过滤文件中未来的新元素,而不需要在regex中定义显式排除规则。

我采用了不同的解决方案

string[] patternString = Regex.Split(datFileString, "tile_pattern{");
string[] borderString = Regex.Split(patternString[patternString.Length - 1], "border_set{");
patternString[patternString.Length - 1] =
patternString[patternString.Length - 1]
.Remove(patternString[patternString.Length - 1].IndexOf("border_set{", StringComparison.Ordinal));
tilePatterns = new List<TilePatternData>();
foreach (string s in patternString)
{
if (s.Contains("background_color")) continue;
TilePatternData tilePatternData = new TilePatternData();
tilePatternData.LoadFromDatFile(s);
tilePatterns.Add(tilePatternData);
}

然后在TilePatternData类

public void LoadFromDatFile(string datFileString)
{
//tile_pattern{
//id = "10", (string)
//ground = "empty", (string)
//default_layer = 2, (number)
//(x = 72,) (x = { 712, 728, 744 },) (number or table)(only matching the number, have to add in the table)
//(y = 0,) (y = { 384, 384, 384 },) (number or table)(only matching the number, have to add in the table)
//width = 8,
//height = 16,
//frame_delay = 250 (number, optional)
//mirror_loop = true (boolean, optional)
//scrolling (string, optional)(The Ones in the test file do not have a repeat_mode
//repeat_mode = "none", (string, optional)
//}
Regex parts = new Regex("\s*(\w+)\s*=\s*"(\w+)"");
Match match = parts.Match(datFileString);
//Debug.Log(match.Success + " " + datFileString);
while (match.Success)
{
string pram = match.Groups[1].ToString();
string value = match.Groups[2].ToString();
// Debug.Log(pram + "=" + value);
switch (pram)
{
case "id":
id = value;
break;
case "ground":
Enum.TryParse(value, out ground);
break;
case "scrolling":
Debug.Log(pram + "=" + value);
Enum.TryParse(value, out scrollingEffect);
break;
case "repeat_mode":
Enum.TryParse(value, out repeatMode);
break;
}
match = match.NextMatch();
}
parts = new Regex("\s*(\w+)\s*=\s*(-*\d+)");
match = parts.Match(datFileString);
// Debug.Log(match.Success + ": \s*(\w+)\s*=\s*(-*\d+)");
while (match.Success)
{
string pram = match.Groups[1].ToString();
string value = match.Groups[2].ToString();
// Debug.Log(pram + "=" + value);
switch (pram)
{
case "x":
int.TryParse(value, out startX);
break;
case "y":
int.TryParse(value, out startY);
break;
case "width":
int.TryParse(value, out width);
break;
case "height":
int.TryParse(value, out height);
break;
case "default_layer":
int.TryParse(value, out defaultLayer);
break;
case "frame_delay":
int.TryParse(value, out height);
break;
}
match = match.NextMatch();
}
// x = { 712, 728, 744 },
parts = new Regex("\s*([xy])\s*=\s*{(\s*\d+,*)*\s*}");
match = parts.Match(datFileString);
Debug.Log(match.Success + ": \s*([xy])\s*=\s*{(\s*\d+,*)*\s*}");
while (match.Success)
{
Debug.Log(match.Groups[2].Captures.Count);
string pram = match.Groups[1].ToString();
string[] value = new string[match.Groups[2].Captures.Count];
// work in progress to extract the table values
}
parts = new Regex("\s*mirror_loop\s*=\s*(\w+)");
match = parts.Match(datFileString);
//Debug.Log(match.Success + ": \s*mirror_loop\s*=\s*(\w+)");
if (!match.Success) return;
bool.TryParse(match.Groups[1].ToString(), out mirrorLoop);
Debug.Log(mirrorLoop);
}

可能还有一种方法可以进一步简化它。

最新更新