C# Command Line Arguments Parsing Strategies

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so over the years I've noticed quite a lot of people really aren't sure of good ways to do parsing of command-line arguments so is when you when you run a tool that you've written there are usually some additional stuff at the end of it that you want to use to modify the behavior of when it runs if you're developing you probably you're familiar with using git and that's a perfect example of it there are different options like git clone and get add those are arguments that would need to actually be processed parsed there's different approaches to doing this and so I'm gonna get into some of the more simpler ones and then cover also a few already existing libraries for more sophisticated approaches than what I'm going to be showing off here so let's start this off with one of the more basic approaches to this and that's that not even actually really process the arguments at all let's just change this to just straight-up print the arguments so they're not actually being processed beyond just being used I don't know why I did that because we're actually going to want to run this so that we could see the output but also type in things so what is it source free pose and then I called it command line arguments oh one more directory to get into yeah so you can see that in this instance I said hello world just like you would expect out of the standard hello world but it actually got the arguments from what we passed into it so we can do similar things like hello YouTube and it'll print it out there you know nothing super fancy they're not really modifying the behavior it's just regurgitating it back out we want to actually do things with this now one of the simpler approaches to this kind of stuff is to grab the very first part of it oh yeah that should do it I think so then let's just print these out just so that we can see what we're working with and you can see it did actually split these up so then we can do a switch over the verb it's usually a good idea but not required to convert it to either uppercase or lowercase exactly what you do depends a little bit on what language you're using and what kind of environment you're dealing with the way everything is developed for the.net libraries which if you're using c-sharp you're using dotnet you want to do an uppercase conversion and that has to do with some system locale stuff like if you're in an english-speaking area it doesn't really matter but for other parts of the world just the way it's set up you really want to do uppercase conversions so that's what I'm going to be doing here lookup on whatever language you're doing what is the generally accepted practice though so we can switch over this and let's do one where it's hello and I'll fill at it in just a moment and another one where it's so goodbye and I'll fill that in Y as well now seeing as we have a massive pool of options I don't want to say infinite because there's only a certain amount of characters that can fit it in any string but you want to have a default where you catch unknown verbs in this case so let's just do okay and we need to break on that one as well so for hello let's do and for goodbye we'll do a similar thing now if we try to run what we just ran you're gonna see that it doesn't actually know what to do with this because while it was originally just regurgitating it back now it's actually looking at the very first argument in this case the YouTube as a verb as a designator for what to actually do and it doesn't know what to do with it because we didn't actually define YouTube as one of these verbs but let's actually switch this over to hello world and similarly if we do let's totally garbled the casing just to show that that works as well goodbye let's see that works as well as expected so this approach tends to work pretty well when dealing with really simple really simple command-line tools if you really only have some basic choices this is going to work chances are you're going to be dealing with something more sophisticated than this however and so the next approach is actually going to be able to handle modifiers upon the verbs actually the next two approaches I'm going to be showing sort of two approaches to the same level of complexity they're pretty different in how they actually work though and which you'd want to use will hopefully be pretty apparent by the end of this so let's actually switch this over to back out let's let's like let's include this actually using system and collections they call it collections stack string and this is just going to be art now there's something a little funky I've actually got to do for this it's a new stack ring I could have been left alone but it just sort of drives me nuts so it's Argus verse I think and that's because otherwise it'll fill the opposite way of what we want for this you don't want a queue either queue would be created the right way without reversing it but there's a operation that you really need stack behavior for I'll I'll point out when that is though so in this case let's let's leave that as is for now and we'll do string verb just leave that as is in the well let's do this ahead of time so if our eggs length our arms count count is greater than or equal to one so that there's something you can actually pop off for those of you who know c-sharp a little bit better I'll I know what you're thinking I'll change that in just a second this is easier to understand for the people who don't know what you're thinking actually no this has got to stay up here but then we do verb equals args and then just I'm mixing up my programming languages there we go and then much like before just so that we could see what we're working with let's print the verb back out yeah use of unassigned local variables so let's do a reasonable default of a little let's handle it this way actually is an empty string if it can't actually pop something off just so that we can actually print this out correctly and for instead of rest you know the rest of the arguments because we actually popped off from the stack we removed the actual verb off of it we can actually just put the args here and because the verb was removed it will just use everything else the rest of it let's go ahead and build that and this should work exactly the same and it does we have the verb of hello and then everything else just get sort of packed together attached to the end of it so it behaves the same way as the previous one obviously this is a little bit more complex than that you're actually creating a whole stack if this is all you need you don't want to go with this of complexity but now we're gonna actually build upon this one of the first things I'm actually going to do is have to remember how this actually works there's also a try pop operation that so if and it's hard let's see what this actually does yeah so it returns the boolean and then we have an out parameter so we're gonna do actually I should be able to do this here let's let's remove that and I should be able to put this here so switch no I won't be able to so I do got to leave this but we can you out of verb no cuz that's gonna fire if it actually is able to pop so let's change that to a negated one so what's going to happen with the Tri pop is if it's actually able to pop something off it will assign verb to whatever it was able to pop off and then it will return a troop because it was able to and that's what we're testing for here if it's not able to pop something off then it will return a false and nothing will be set and so that behaves the same and if we remove all of the command-line arguments yeah because it wasn't able to actually assign it in the try pop instead what happens is the verb is left on assigned and we should probably handle that by throwing an exception or just quitting there yeah now one of the advantages of a of the stack approach is that you can repeatedly remove modifiers off when they're supposed to be presented in a standard order sort of more like natural language if you're using a positional grammar at least and of course English does that so this tends to be sort of more familiar to English speakers well it's quite a few other languages that work that way like even if they use a system of declension there's typically just a standard order that the words are presented in anyways well did you generally what you wind up seeing so we want to actually get additional arguments off of this for that let's do we'll create another string for a modifier we'll only do this one level because once you actually know how to get modifier out of it you can just repeat the process to get additional modifiers so it works in the exact same way no matter how deeply you nest it and let's not pop that off just yet yeah this is fine we're gonna do another check or yeah we'll do it this way if our stripe huh out modifier this time and so obviously the case where it's not able to needs to be handled and that's just what we wrote before otherwise we need to switch over the modifier and of course that's not very interesting on it oh there we go that's not very interesting on its own so let's actually modify this up a little bit so that it's a bit more unique and that you can actually tell a the modifier was registered as well and for that just some simple coloring will do I don't want to reset the color so that everything else is in blue afterwards and [Music] so if we pull this back up we do a hello world it does do oh yeah so I forgot the part I'll do the modifiers first though so let's do hello everyone nope I mess something up Oh cuz I'm I'm getting all composite yes this stays like that and we need to do what's what's the rest of this there we go so I just wrapped things up the wrong way you can see the hello everyone did its special thing where it was blue text if we right ello YouTube it does its special thing with the text and if we write hello world this should fail yes this did the same thing as before and that's what part we need to fix so we remove the modifier so that we could handle that separately as opposed to handling the entire stack like we did before where it just printed you know grouped everything back up and printed it this is why it needs to specifically be a stack because if we do if we reattach it and it's a queue what we'll wind up happening is it's put at the very end but we removed it from the very beginning and want to put it back on the beginning that's why we need the stack that's why we needed to do the weird reverse thing so what we're going to actually do is well args push so that it goes back on there and push the modifier back on to it now Ava does it properly and like I said this can pretty much be done to any level of nesting you can have I don't know I'm sure there's some technical limitation where the stack is just like I'm too large this needs to stop but for all intents and purposes all practical situations you will be able to do this as deeply nested as you need to pushing anything that you didn't need that wasn't a modifier that was a normal argument back onto the stack and then using the the stack whatever remains as the rest of the arguments and like I had said before this approach works really well when you have a more strictly ordered set of arguments if instead you're doing something like flag options and this is not going to work flags really have the ability to be placed anywhere within the arguments and are understood quite differently from this positional approach so and it I'm gonna put in a little jump cut get this all cleaned up and we'll actually show how to do at least one approach a rather simple approach to flag options so this is gonna wind up being pretty much the simplest way to do handling of flag options I would not recommend this if you need very sophisticated flag options like setting different flags to different specific values but if the only thing we're going to need is to check for the presence of those flags this will work if you need beyond this that's when I'll be covering a library that I think does an absolutely amazing job of handling this kind of stuff so for this we're actually going to need a helper function and let's won't need to store this or that just drives me nuts actually can I store them here is this a thing I never actually tried to do this oh yeah cuz then I wouldn't have access to this right right why can assign them there so yeah let's yep so that I can do it without actually passing them around not like that's a big deal but it just cleans things up a little bit so then we're going to do a helper what we'll need the flags to so it looks like well it's actually creating another one of these hold flags and that will hold the flag as the args will be the rest of it well will initially be everything and then afterwards will be everything that wasn't a flag so I'm gonna do for each and then just string Arg in artists and okay so the problem with that is Goods not going to obey at the beginning needs to be a double - so I don't want to do that let's get some reg X going on here we'll need any options and then it's Matt then we want to add that to flag so flags well add argh and so that'll be it for now or just make sure that this correctly gets the flags and then actually go through removing them so let's do harsh legs and then console.writeline flags oh yeah because those are collections I need to join them so string join from size is always right [Music] let's just do that for a now house so it doesn't complain or no wait I can assign that and here act in here actually so this would be desperate I'll just put it up here okay so both of these should be correctly in artists and if we just change one of them yes it was put in two flags it was correctly recognized as a flag and then just to make sure this doesn't happen because if we just used string contains this would be recognized as a flag and it's obviously not and it's not recognized as a flag good good that's correct behavior so obviously leaving that in the args is not good that's not helpful because it'll be processed as an argument as well and that's not so then we're gonna have to actually do for each line in Flags you have to use a new iterator because if you remove the anything from the collection that you're iterating over for good reason c-sharp complains about that like you probably don't want to do that that's a really stupid thing to do so we're gonna iterate over the other container that now just has the flags and for every flag actually remove it from the args container this way we don't actually modify the same container that were iterating over and it split up appropriately now so then we're going to have to actually build up the flags for this for the first time in this video we're actually going to create another file and this is going to be a special enumeration yeah just leave them there it's not really gonna affect anything so there's a special attribute for doing things like this and other stuff but it's useful for this the flags attribute or black yeah it's the flags attribute yeah sort of trip myself up since they're using the same name there as well but what this allows you to do is special bitwise operations upon them and in order for that to work right you've got to be a little bit careful about how you actually assign the things here so let's do just a help flag for now and then I think there's got to be a default flag as well I forget let's try it without it so we'll put this yeah we'll put this here let's do Lang's have this actually return the the flags now now create the flags and actually we can do this part in one shot so let's actually define this here and when we okay we're good now oh yeah now yeah when we remove flag we also have an opportunity to match the flag to aid any known defined flag and actually do the bitwise operations so we're going to have another switch statement in here switch flag to upper for the default case we're just going to break out because then this handles everything that needs to be handled for while we just defined help for now although this will need that put in the break and we're actually going to do is flags and then a bitwise or now in c-sharp which I'm using you can combine this what's an assignment operator so that it there's a little bit less typing and we're going to do the help flag now I should need to include that oh yeah cuz I have flags written so many other places that it's got to do this so use of unassigned local variable that's not why not so I do got to do with default I will just put this in the important thing about the default is that it's zero unless you know that there's a flag that will absolutely have to be put in there and that if somebody just writes it in it's just sort of redundant I recommend against that approach just do the default of 0 and it's fine so we'll do Flags default and now that's handled properly so well no we do still want this so now we want to change this over to actually writing this in which case we don't actually mean that leash train join so it's default flags because you know the world flag that we have here is obviously not one that we defined but if we do help instead you can see that the flags is actually set to help and this should work in either direction so if we put help in a different spot it still works the flags are still recognized as help now if we take this one step further and add in another flag so I don't know info now if we just have the help one it does a health check that info actually works correctly and that yep now if we put both of them down you can see that it does register that both flags were actually found and that's because a bitwise or is happening so the D Flags attribute here as well as the exact layout that's important but get into those details in a little bit allow us to actually have multiple flag asset even though this is a single value and not an actual collection it's essentially a bit field that we're creating and depending on which bits are set it registers as different Flags actually having been set hence the you know Flags name and as a result really useful for actually doing command line flags now we don't do anything with these yet I'm just building up the actual flags you know to where you can see how this works so when I add one more in here and I don't know what I'm gonna call it yet well this works we can keep with the hello world theme now you may have been tempted to write three here because that's you know normal ordering for numbers the thing is though and why I've been explicit about these is because this is a bit field we do need to actually ensure that different bits are being set we actually need a for what you do for this is dyadic but you just keep increasing it by powers of two so the next one would be eight and the one after that would be sixteen and it just keeps going like that if you for some reason have sort of a reduced flag yeah I can show that off as well so if we do a full info and that'll be three so this way you you guys can see the way fully the way this works because there is a legitimate use for assigning a number that sets multiple bits at once so let's do it was full info and we have the other one which was great well look at that it's the exact same one but this time it says full info because we assigned a specific name for if both of those were combined and if we actually write full info this time it does the same thing so we can well what I was gonna show will be obvious when I start actually handling these anyways so let's actually start to write the handlers for these we have a help function or a help flag rather so let's actually put the matching help function this yeah okay where we print out the different different flags and I'm not going to do anything fancy with descriptions or anything other than this one see it for help okay obviously we need to handle this as well so let's do switch over the flags the default generally speaking when writing a normal tool if the input wasn't correct so like there's a bad combination of flags or there were no flags and you need one or even more so you need a verb and possibly some flags you probably want to in the default just print the help in this instance we're just not going to just the you know further show this off so we'll just literally do nothing here so we'll also need flags and help will call the help function or method I guess really is object-oriented programming so it'd be a method but it's a it's a function so that prints out the help now if we do full info ah so that's not quite the behavior we want yet there's a few approaches to this for one we can break away from the switch behavior and do if there is actually a way to test if a specific flag is set rather than the switch-case blocks that looks I'll show the older way first and if we do what does it flags and the one you want to test for so this would be flags help whatever and I think you can just test for equality against help and everything just sort of works Oh cuz the comparisons having first and then the end is happening afterwards that's that's not wait wrong AB okay yeah still the the bitwise and is happening first and that's not what we actually want to have happen so let's do this instead and pretty sure this should work now and say that yes it asked for help but the exact match to the flags was not made so if you if you're really just concerned if a specific flag is set rather than the full combination of flags this approach might mean more your thing now I forget what your version this happened in but they simplify this a bit and it can actually be written as what is it Flags and yeah has flag so we can put the flag help and this worked again obviously this is quite a bit more readable but all it's doing under the hood is exactly what I've just had there before so if for whatever reason you're not able to use this method I go ahead and do what I did before they work the exact same way now let's ride out the rest of these and I can show a little convenient way to do the full health once these are written so I also mean info normally you would want to do reflection for this kind of stuff I'm not gonna bother because this is just about command line arguments and parsing them not about how to do a whole tool so we're just going to cheat a little bit now obviously we need to handle the info as well so let's do that oh now drama so can you help you get the help if we do info you get the info well we still get nothing for full help you could do a full help one and then test it both flags but it's literally just doing what both of these do anyways so let's actually just combine these now obviously you could just use wherever it is full full info and then call help info you usually presented before it and break that's I mean that's part of I'm hanging of something else but yeah there we go we have both of them combined and just because I did that little slip-up let's just comment this out and I can show that it still doesn't do it you know it did exactly what it did before you can use the wrong flag yeah there's still there's still nothing let's add that back in if you don't actually have a unique name for the combination of flag is set what you would want to do is actually perform the bitwise or right in the case statement you can see that works and if we do the separate help and info exact same thing exactly what it should so let us do the greet where we actually use the rest of the arguments what are the college's Argos so if we do just greet it's just gonna say hello that's you know probably not the behavior you actually want but maybe it's fine if we then put in something like world hey that's fine mix up the order of these it should still work and of course it does that's [Music] because this will show off a little bit better that it really does not care at all where the flag is set there you go obviously if you were assigning a variable to one of the flags so that as the flag exists for the assignment of a specific property while all the rest of the arguments are separate this approach is not going to work for you but this this and the stack approach I demonstrated earlier are pretty on par with the level of complexity they can handle just one cares about position while the other cares more about what the flag is then moving on to the library that I talked about if you need could you know considerably more sophisticated command line parsing where the actual assignments to different Flags this from my experiences seems to be the best option for dotnet stuff whether you're using C sharp or F sharp probably visual basic as well it is actually fully supported by by this library I'm not gonna get into showing it off just because there's you know demo stuff yeah so visual basic is supported but there is demo stuff going on here that you can look at there some you know quick start as well and they have a basic wiki basic as in the wiki itself is literally just one page but it does cover quite a depth of information and you probably know how to use everything in the library just just from this so the information in the wiki is not basic by any means I'll have a link to this in the video description but it's really easy to find and the NuGet package is just straight up called command-line parser it's a it's really good I think super easy to use some really nice features like the help stuff for it is automatically generated for you based on the attributes that you put in there it's a highly decorative thing so you're not coding in a lot of stuff you're just saying like hey this this thing is used to represent a verb and here's the description of it that you can print out your help and it sort of handles the rest of it for you even even the parsing for you just based on declarations that you make which makes it really really nice because this is able to handle very complex command-line arguments without you really doing a whole lot so that's it for this I know this is the very first non meta programming video I've done and I have some general stuff about just programming in general but you know I said several months ago that I wanted to cover some other stuff and obviously with me being a c-sharp and after I've developer as well it made sense to cover some dotnet stuff hopefully you found this helpful please thumbs up and also consider subscribing and have a good one
Info
Channel: Patrick Kelly
Views: 3,691
Rating: 4.6923075 out of 5
Keywords: C#, csharp, program, programming, programmer, code, coder, coding, develop, development, developer, developing, command line, arguments, args, command line args, command line arguments, parsing, strategies, techniques, methods
Id: cX6M_h5OCR0
Channel Id: undefined
Length: 59min 25sec (3565 seconds)
Published: Fri Jun 29 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.