Reputation: 914
I'm whipping up a small program that controls a 3D printer. When I send it something, it usually responds with an ok
, but if something's not okay, it sends something like this:
T:221.0 /220.0 @:0 W:1
I could easily parse it if it had proper delimiters, but using space isn't reliable because of the string 221.0 /220.0
. Consequently, if I use space as a delimiter, /220.0
may be treated as a key-value pair but there is no key since it's under T
. I was planning on getting the index of every colon and simple start 1 character behind it but the key length is also variable. For example:
T:221.0 /220.0 B@:127 @:0 W:1
B@
is now two characters long.
I did some research but all of what I found had proper delimiters like a URL with data.
http://www.niederschlagsradar.de/images.aspx?jaar=-6&type=europa.cld&datum=201311161500&cultuur=en-GB&continent=europa
I was planning on getting every colon's index then searching backwards for a space when a colon is found which would serve as a starting point. Likewise, the next key-value pair's start point would serve as an ending for the previous one. But, I'm not sure if it's the right approach.
Main question: How do I parse a string without proper delimiters? I don't really have specific requirements. Be it an array or a list, separate variables for key and value or just shove everything into an array such that
string[] data = {key1,value1,key2,value2,key3,value3};
Update: Here are the key-value pairs from the second example:
Key:Value
T:221.0 /220.0
B@:127
@:0
W:1
Some more samples:
T:221.0 /220.0 B:85.7 /120 B@:30W @:0 W:8
Key:Value
T:221.0 /220.0
B:85.7 /120
B@:30W
@:0
W:8
Here's another more complicated one:
T:171.4 /220.0 B:90.3 /120 T1:171.4 /220.0 B@:30 @:12W W:6
Key:Value
T:171.4 /220.0 // Temperature of first nozzle heater
B:90.3 /120 // Temperature of the hot plate it's printing on
T1:171.4 /220.0 // Temperature of the second nozzle heater if it exists
B@:30 // Raw power consumption of hotbed (unit depends on config)
@:12W // Power of of nozzle in Watts (unit depends on config)
W:6 // Waiting time (in seconds). If the optimal conditions are met and this counts down to zero, printing resumes. Else, reset to 10.
The space at the start of the sample strings are intentional. It does start with a space. For those who are interested, these are the replies of an Arduino Mega running the Marlin 3D printing firmware. These are the replies when the printer heaters aren't hot enough yet to extrude.
Related: How to parse a string to find key-value pairs in it
Upvotes: 1
Views: 715
Reputation: 66389
I would go with this logic:
Code:
private List<KeyValuePair<string, string>> ParsePrinterResponse(string rawResponse)
{
List<KeyValuePair<string, string>> pairs = new List<KeyValuePair<string, string>>();
string[] colonItems = rawResponse.Trim().Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
if (colonItems.Length > 1)
{
string currentKey = colonItems[0], currentValue = "";
for (int i = 1; i < colonItems.Length; i++)
{
string currentItem = colonItems[i];
int spaceIndex = currentItem.LastIndexOf(" ");
if (spaceIndex < 0)
{
//end of string, whole item is the value
currentValue = currentItem;
}
else
{
//middle of string, left part is value, right part is next key
currentValue = currentItem.Substring(0, spaceIndex);
}
pairs.Add(new KeyValuePair<string, string>(currentKey, currentValue));
currentKey = currentItem.Substring(spaceIndex + 1);
}
}
return pairs;
}
Usage sample:
errorBox.Lines = ParsePrinterResponse("T:171.4 /220.0 B:90.3 /120 T1:171.4 /220.0 B@:30 @:12W W:6").ConvertAll(p =>
{
return string.Format("{0}:{1}", p.Key, p.Value);
}).ToArray();
Upvotes: 1
Reputation: 926
From each colon position found,
search backwards until a whitespace character is found
search forward until a whitespace character is found
I would not relate the next key-value pair's starting point to the previous ending one, since there might be several spaces between key-value pairs. I would determine keys and values starting from colon positions only.
Upvotes: 1