 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 that is 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're probably familiar with using Git and that's a perfect example of it. There are different options like Git clone and Git add. Those are arguments that would need to actually be processed, parsed. There's different approaches to doing this, and so I'm going to 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 to 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. 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. One more directory to get into. There we go. So you can see that in this instance it said hello world just like you'd 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 .NET, 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 conversion. So that's what I'm going to be doing here. Look up 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 that in in just a moment. And another one where it's so good. Bye. And I'll fill that in 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 in any string, but you want to have a default where you catch unknown verbs in this case. So let's just do... 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 garble the casing just to show that that works as well. Goodbye. You can 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... Let's include this, actually, using collections. They call it collections. Stack of string. And this is just going to be args. Now there's something a little funky I've actually got to do for this. It's a new stack of string. That could have been left alone, but it just sort of drives me nuts. So it's args. Reverse, I think. And that's because otherwise it'll fill the opposite way of what we want for this. And you don't want a queue either. A queue would be created the right way without reversing it. But there's a operation that you really need stack behavior for. I'll point out when that is, though. So in this case, let's leave that as is for now and we'll do string verb. Just leave that as is. Let's do this ahead of time. So if args length, or args count, count is greater than or equal to 1, 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 pop. Or 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. Verb 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, without 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 and attached to the end of it. So it behaves the same way as the previous one. Obviously, this is a little bit more complex in that you're actually creating a whole stack. If this is all you need, you don't want to go with this level of complexity, but now we're gonna actually build upon this. And one of the first things I'm actually going to do is I have to remember how this actually works. There's also a tripop operation that... So if... and it's args... 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. So 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 do out verb. Well, no. No, because 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 tripop 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 true 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 sent. 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 tripop, instead what happens is the verb is left unassigned. And we should probably handle that by throwing an exception or just quitting. So there you go. 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. It's quite a few other languages that work that way. Like even if they use a system of declency, and there's typically just a standard order that the words are presented in any ways. Not all of them, but that's 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 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 the exact same way, no matter how deeply you nest it. Let's not pop that off just yet. So what we'll do is... Yeah, this is fine. We're gonna do another check or... Yeah, we'll do it this way. If R is tri-pump, 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 in that you can actually tell the modifier was registered as well. And for that, just some simple coloring we'll do. Let's do... I don't want to reset the color so that everything else is in blue afterwards. And... So if we pull this back up, we do have... It does the... Oh. Oh, yeah. So I forgot the part. I'll do the modifiers first, though. So let's do hello everyone. Nope. I messed something up. Oh, because I'm getting all confuzzled. Yes, this stays like that, and we need to do... What's with the rest of this? There we go. So I just wrap things up the wrong way. You can see the hello everyone did its special thing where it was blue text. If we write hello 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 the 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 will 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... args push so that it goes back on there and push the modifier back onto it. Now, it 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 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, 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 I'm going to 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 going to 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 you are 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 we'll need to store this R equals new list string that just drives me nuts. Actually, can I store them here? Is this a thing? I never actually tried to do this. Oh, yeah, because then I wouldn't have access to this. Right, right. Why can't I assign them? So yeah, let's, yeah. So then 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. Well, we'll need the flags too. So let's like, let's actually create another one of these called flags and that will hold the flags. The args will be the rest of it. Well, we'll initially be everything and then afterwards will be everything that wasn't a flag. So we're going to do a for each and then just string arg in args. And okay, so the problem with that is good. Not going to obey at the beginning needs to be a double dash. So I don't want to do that. Let's get some regex going on here. We'll need any options and then is match. Then we want to add that to flags. So flags, well, add arg. And so that'll be it for now. Just make sure that this correctly gets the flags and then actually go through removing them. So let's do parse flags and then console write line flags. Oh, yeah, because those are collections. I need to join them. So string join write. Let's just do that for now. So it doesn't complain. Or no, wait, I can assign that in here actually. So this would be that screw it. I'll just put it up here. Okay, so both of these should be correctly in args. And if we just change one of them, yes, it was put into flags. It was correctly recognized as a flag. And then just to make sure this doesn't happen because if we just use 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 it's not. So then we're gonna have to actually do for each flag in flags. You have to use a new iterator because if you remove anything from the collection that you're iterating over for good reason C sharp complaints about that like you probably don't want to do that. That's 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 we're iterating over and it's 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 in 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 flag... Yeah, it's the flags attribute. 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 flags. Have this actually return the flags now. Create the flags and actually we can do this part in one shot. So let's actually define this here and when we... We're good now? We're good now. Yeah. When we remove flag, we also have an opportunity to match the flag to a 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 what? We just defined help for now. All of this will need that. We'll put in the break. And what 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 with an assignment operator so that it... there's a little bit less typing. And we're going to do the help flag. Now I shouldn't need to include that. Oh, yeah, because I have flags written so many other places that it's got to do this. So use of unassigned local variable. That's north bueno. So I do got to do a default. We'll 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'd recommend against that approach. Just do the default of zero 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 need the string join. So it's default flags because 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 help. 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 the flags attribute here as well as the exact layout, because that's important, I'll get into those details in a little bit, allow us to actually have multiple flags set. 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 it's 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 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 four. What you do for this is dyadic, but just keep increasing it by powers of two. So the next one would be eight, and the one after that would be 16, 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 full info, and that'll be three. So this way 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 green. 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 going to show will be obvious when I start actually handling these anyway. 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 flags. And I'm not going to do anything fancy with descriptions or anything other than this one. So you have full help. Obviously we need to handle this as well. So let's do a switch over the flags, the default. Generally speaking when writing a normal tool, if the input wasn't correct. So if like there's a bad combination of flags, or if 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 to, you know, further show this off. So we'll just literally do nothing here. So we'll also need flags and help. We'll call the help function, or method I guess really. This is object-oriented programming, so it'd be a method. But it's a function. So that prints out the help. Now if we do full info. 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 ifs. 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 is it? Flags and the one you want to test for. So this would be flags, help, whatever. I think you can just test for equality against help and everything just sort of works. Oh, because the comparison's having first, and then the end is happening afterwards. That's not... Wait, wrong end? Okay, yeah. Still, the bitwise end 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 be more your thing. Now, I forget which version this happened in, but they simplified 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, go ahead and do what I did before. They worked the exact same way. Now, let's write out the rest of these, and I can show a little convenient way to do the full help. Once these are written. So we also need 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. And obviously, we need to handle the info as well. So let's do that. No, wrong one. You help. You get the help. If we do info, you get the info, but 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 info and then call help. Info usually presented before it and break. Well, that's, I mean, that's part of, I'm hanging on 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 what, you know, it did exactly what it did before. Even though I used 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 flags set, what you would want to do is actually perform the bitwise or write 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's do the greet where we actually use the rest of the arguments. What do I call it? Just args. 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. Let's, um, because this will show off a little bit better that it really does not care at all where the flag is set. And there you go. Obviously, if you are assigning a variable to one of the flags, so that is 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, you know, considerably more sophisticated command line parsing or factual assignments to different flags. This, from my experiences, seems to be the best option for .NET stuff, whether you're using C-sharp or F-sharp, probably Visual Basic as well. It is actually fully supported by this library. I'm not going to 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's 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'd probably know how to use everything in the library 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 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 declarative thing, so you're not coding in a lot of stuff. You're just saying like, hey, this thing is used to represent a verb and here's the description of it that you can print out for help. And it sort of handles the rest of it for you. Even the parsing for you just based on the 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-programming video I've done. And I have some general stuff about just programming in general, but I'd said several months ago that I wanted to cover some other stuff. And obviously with me being a C-sharp and F-sharp developer as well, it made sense to cover some .NET stuff. Hopefully you found this helpful. Please thumbs up and also consider subscribing and have a good one.