简体   繁体   中英

Regex pattern matching with multiple groups C#

I have a file that looks similar to:

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",
}

I have it loaded into a string called datString . I am trying to match all of the tile_pattern parts in a single regex expression.

This is what I have so far:

//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();
        }

which returns a match length of 138 (should be 4830) at a glance through my debug log the only ones that seem to be missing are the 32 patterns that have x = { 712, 728, 744 }, I have not figured out how to add this into my capture group yet any help would be appreciated. Also how would I add the 3 optional fields to make sure if the are all there they would get matched?

Need to add to pattern

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

It appears your file input is from a Solarus Quest Tileset data file. According to the specs :

This syntax of the tileset data file is actually valid Lua.

Rather than using Regex, consider using a Lua parser. NLua seems to be able to do a lot with Lua, although it may be a bit much for just parsing variable list notation.

See also: Easiest way to parse a Lua datastructure in C# /.Net

Your regex is really much more complex than it has to be... now only you and god know what it does - after a week only god will;-)

Try this regex: tile_pattern\{(?:[^{}]|(?R))+\}

Please also make sure to set the correct flags (because I don't know the C# syntax for that)

  • global (do not return after the first match)
  • extended (ignore whitespaces)

Also refer to this sample https://regex101.com/r/zqcOBY/1

This also takes care of filtering future new elements in your file without the explicit exclude rules you define in your regex.

I went with a different solution

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);
            }

Then in TilePatternData class

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);
        }

There may still be a way to simplify this even further.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM