- Home /
Parsing a Custom Scripting Language
I'm creating a parser to import data into Unity from text files that use a custom scripting language created by someone else. I only need to import the data at editor time, so speed and performance is not a huge concern.
Now I can extract data from a single line easily using String.StartsWith() and String.Split(), but I'm not sure how best to do more complex multi-line arguments. Here's the data structure I'm trying to extract from.
KEYWORD ID {
SCALE_XY 32, 32;
CYCLES 6;
BMAPS wnoise1_map, wnoise2_map, wnoise3_map, wnoise4_map, wnoise5_map, wnoise6_map;
DELAY 3,3,3,3,3,3;
}
I want to find the line that starts with "KEYWORD" then parse the ID after the keyword and all values between the curly brackets. Excluding commas, semicolons, etc. Putting each argument in a string in an array.
Here's what I've come up with so far:
StreamReader stream = File.OpenText(filename);
string entireText = stream.ReadToEnd();
stream.Close();
using (StringReader reader = new StringReader(entireText))
{
string currentLine = reader.ReadLine();
while (currentLine != null)
{
if (currentLine.StartsWith("KEYWORD"))
{
string text = "";
// Read until closing curly bracket.
while (!currentLine.EndsWith("}"))
{
text += currentLine;
currentLine = reader.ReadLine();
}
// Split text up by semicolon.
string[] textArray = text.Split('{', ';');
}
currentLine = reader.ReadLine();
}
}
Anyone know of a better / easier / simpler way to do this? I've experimented with regular expressions, but that doesn't seem to be any easier to get working.
At the moment I'm thinking maybe I should use String functions in combination with a state machine? First find the correct line with String.StartsWith() then use it again to check each line between the curly brackets after that for other keywords and so on, etc.
Yeah, I think the easiest way IS to use Split... Use StartsWith to get "$$anonymous$$EYWORD", then use Split to split it by either \n (new line) or ; (semi-colon), then youll end up with each of those 4 lines in its own string, you can then remove from \t (however many tabs you have between each word and the values), so youd then end up with a string array of JUST your values with your commas, but it shouldnt contain any semi-colons at this point
From there, you can decide how you wanna continue to split and handle your data for whatever you actually need to use it for, split by a comma to get specific values if needed, use Find to see if you have specific values, etc...
If you post the current code you are using to parse the file, I (or someone else) may be able to provide you with some example code to help you out as well.
So far I've been using StreamReader to load all the contents of the text file, and then StringReader.ReadLine() to go over each line.
void ParseFile(string filename)
{
StreamReader stream = File.OpenText(filename);
string entireText = stream.ReadToEnd();
stream.Close();
using (StringReader reader = new StringReader(entireText))
{
string currentLine = reader.ReadLine();
while (currentLine != null)
{
// Parse current line.
Parse$$anonymous$$eyword(currentLine);
// Go to next line.
currentLine = reader.ReadLine();
}
}
}
void Parse$$anonymous$$eyword(string text)
{
if (text.StartsWith("$$anonymous$$EYWORD"))
{
Debug.Log("$$anonymous$$eyword Found: " + text);
}
}
This of course doesn't work for multi-line arguments though. I've tried feeding the entire text into my parsing function, but then it doesn't return any results at all? Also, if I get this working I'm not sure what would stop it from returning everything in the entire file after the keyword? Would I then use String.EndsWith() or something to stop it?
You could come up with a token to use to denote a multi line arguement. something like '/' that you could put at the end of a line to signal to your parser that you need to read the next line, too.
When you do you ReadLine call, you could check if the string ends with your token, and if so, call ReadLine again (obviously you'd want to continue to ReadLine while the string you just read in ends with your token).
Then you can concatenate all your strings into a single string and parse that.
So you're going to want to work with generics here, and I have a good answer for you that does not involve string parsing, but I need to know why you're passing in your data like that.
I realize now my earlier wording might have been a bit misleading. This "custom scripting language" was not created by me. The scripts were created for another program completely unrelated to Unity. I'm just trying to convert select parts of the data in these scripts to something I can use in my own C# classes in Unity. A total conversion of the data is not necessary or even possible. I just need to extract the relevant parts I need.
I should also note that performance is of little concern to me here because this is all being done in the editor and not at run time.
realize now my earlier wording might have been a bit misleading. This "custom scripting language" was not created by me. The scripts were created for another program completely unrelated to Unity. I'm just trying to convert select parts of the data in these scripts to something I can use in my own C# classes in Unity. A total conversion of the data is not necessary or even possible. I just need to extract the relevant parts I need. I should also note that performance is of little concern to me here because this is all being done in the editor and not at run time.*
Awe, darn, I was hoping you could have at least put a delimiter in between your keys.
I was going to say take that key and put it in the in a dictionary, then use the values as a list in the dictionary. Then you could have invoked a function using the keys '$$anonymous$$EYWORD' with the values as passed arguments. https://stackoverflow.com/questions/4233536/c-sharp-store-functions-in-a-dictionary
I didn't realize you're only looking for '$$anonymous$$EYWORD' if you were checking, so I hate to say it the way you're currently doing it is the best way.
Your answer
Follow this Question
Related Questions
iPhone System.IO.File.Exists() not working 1 Answer
[SOLVED] Bad PKCS7 While encrypting a file 1 Answer
Is accessing user documents folder possible on Unity3D? 0 Answers
CaptureScreenshot writing to Phone, but persistentdatapath linking to the external card. 0 Answers
Resources Load to open pdf is not working anymore in Android 7 0 Answers