There's no such thing as a stupid question, but they're the easiest to answer.
JoinTour
Login
Search
 
DOS/PDA/Other
Tag Cloud
adware audio bios blue screen boot bsod computer connection crash dell driver drivers email error excel firefox freeze google hard drive hardware hijackthis install internet laptop linux malware network no sound outlook problem reboot router screen server slow sound speakers spyware startup trojan usb video virus vista webcam windows windows 7 windows vista windows xp wireless
Search
Search for:
Tech Support Guy Forums > Operating Systems > DOS/PDA/Other >
Solved: Random Letter Generator - Questions

Tip: Click here to scan for System Errors and Optimize PC performance
[ Sponsored Link ]

Closed Thread
 
Thread Tools
scrfix's Avatar
Computer Specs
Senior Member with 249 posts.
 
Join Date: May 2009
Experience: Computer Repair Expert
01-Jul-2009, 11:56 PM #1
Solved: Random Letter Generator - Questions
I am curious as to why this script works. I found a little bit of the code on another website and modified it however not sure why this actually works:

Code:
@echo off
setLocal EnableDelayedExpansion
set str=AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz.-_
set /a P=!random!%%55
set str=!str:~%P%,1!
echo %str%
EndLocal DisableDelayedExpansion
setLocal EnableDelayedExpansion: This is normally set to allow escaped characters more than once however this code has no escaped characters yet when I remove it the code states I am missing an operator. This means that it must be due to the following lines ie. the !'s in those lines and because of the /a. Do we need this because we are using the !!'s? Why?

set /a P=!random!%%55: If I read this correctly it says set P to 55 and then execute a random number. Now I believe this means execute a random number from 1 - 55 (in which case I found a more efficient method of writing my random number generator in the previous thread and it answers my question as to whether a %random% or in this case !random! number will generate a number lower than 1. My belief and I could be wrong is that the %random% variable will generate a number between 1 - 65535 based upon the time. However that is just a guess.). I just need confirmation that I am correct or wrong about this line. If I am wrong please let me know what this really says. For this particular line, is there any different to me writing this: set /a P=%random%%%55
It works either way. Is there any benefit to the set /a P=!random!%%55?

set str=!str:~%P%,1!: Now, this line to me says take the string. AaBbCc, etc. and start out at the nth character and display just 1 character. It is in between the !! because we are utilizing a variable within a variable so it waits until the end of the line before it executes. Okay, this I understand. I would take this out but I am sure it will help someone else. I love this place. Write out what you think things are and you just start understanding them. Once again everyone (Squashman and Jerry mainly. Thanks for your help. Two weeks ago, I would not have been able to look at this and break this down.)


SetLocal DisableDelayedExpansion: The original code did not have this in it. The original code worked without it however I added this and then it it added an extra blank line at the end of the return. Why?
__________________
Wayne Leiser, Spectacular Computer Repair Computer Repair, Computer Services
World Famous Gift Baskets: Gift Baskets, Corporate Gifts
Resources LLC: Water Treatment Coagulation, Water Recycling
TheOutcaste's Avatar
Computer Specs
Distinguished Member with 5,315 posts.
 
Join Date: Aug 2007
Location: Oregon, USA
Experience: Intermediate
03-Jul-2009, 05:41 PM #2
SetLocal EnableDelayedExpansion
This has nothing to do with escaped characters. What it does is change the way that the command interperter replaces variables with their values.
When using the percent symbol to denote a variable, the command interpreter replaces the variable name with the value of the variable when it processes the line.
When Delayed Expansion is enabled, and you use the exclamation point instead of the percent symbol, the command interpreter replaces the variable name with the value of the variable when it processes the command.
More on this later.

set /a P=!random!%%55
There is no need to use exclamaiont points here except for readbility, to avoid having three percent symbols in a row.
set /a P=%random%%%55 is exactly the same in this usage.
Set /? says %random% returns a number between 0 and 32767. Since it didn't say inclusive, I'm assuming it will never return 0 or 32767. Have to run a loop to test that and see if it ever does.
I'm not sure if it uses the current time for it's seed, or something else.
The reason you get the error when you remove the SetLocal statement is because of the exclamation points. The exclamation point is the NOT unary operator, unary meaning it affects the following operand. Unary operators are processed first, so they are replaced with the value of the unary operation before the rest of the line is processed, i.e., they become an operaand.
NOT(random) will always be 0
So the line now looks like this:
Set /A P=0 NOT(missing) % 55
The missing operator is between the 0 and the next NOT. There is a 2nd error in that the 2nd NOT operator is missing an operand, but it never gets that far in it's processing to show that.
This is the same as writing 2 3 + 4. There is no operator between the first two operands.
When used with Set /A, the percent symbol is the Modulus operator. (Remember that percent symbols must be doubled when used in a batch file)
So the line is this:
Set /A P=random Modulus 55
A Mod B means divide A by B and return the remainder, so this line takes a random number, divides by 55, and returns the remainder. So P will be a number between 0 and 54, inclusive. Or 0 <= P <= 54

set str=!str:~%P%,1!
This is the reason for using Delayed Expansion. The command interpreter wasn't designed to handle variables inside of variables, so this won't work:
set str=%str:~%P%,1%
It's seen as this:
set str=%str:~%P%,1%
So it takes a substring of str, but since there is no start or length specified, it expands to the full string.
It adds the letter P to the string
Then it adds the variable named ,1. Since this is most likely not defined, it's null.
So this line just adds the letter P to the end of the current value of str and you get this:
AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz.-_P
You can use this however, and delayed expansion is not needed:
Call Set str=%%str:~%P%,1%%
This works because of the way the command processor scans lines for variables.

The code has Endlocal DisableDelayedExpansion while your text has Setlocal DisableDelayedExpansion.
Using the enable/disable commands with EndLocal doesn't work. While this doesn't generate an error, you can't enable or disable expansion or extensions with an EndLocal statement. It doesn't seem to add an extra line for me, for I don't have an anser for that.

How delayed expansion works, and why it's needed.
The first thing the command interpreter does is to scan the line for variables. Here's a psuedocode version of what it does:
  • :Start
  • Get Line from file
  • Set position to 0
  • :Scan
  • Increment position by one.
  • If at end of line (EOL) goto endscan
  • If the character at position is the percent symbol:
    Remove it* (replace with NULL), and save the position in the line as the potential start of a variable name.
    • :FindEnd
    • Increment position by one
    • If the character at position is whitespace or EOL:
      Delete saved position and goto Done (not a variable, or it's a loop variable)
    • If the character at position is not a percent symbol, goto FindEnd
    • If there is no text between the saved and current position goto Done (not a variable, just a percent symbol)
    • Remove percent symbol, and save the position in the line as the end of the variable name.
    • The text between the saved positions is a variable name, so look it up and put it's current value into the line.
    • :Done
  • Goto Scan
  • :EndScan
  • Remove NULLs in line.
  • :Execute
  • Parse line to get command
  • If at EOL goto Start
  • If Delayed Expansion is enabled, expand variables surrounded by Exclamation points
  • Convert command to machine code
  • Execute command
  • Goto Execute
*This is why percent symbols must be doubled in a batch file. Why they did this differently for lines read from a file than how a line typed at the prompt is anybody's guess

The key here is that variables are expanded for the entire line before the line is executed.
Example:
Code:
Set first=2
set second=3
set /A sum=%first% + %second%
@Echo %Sum%
When executed, you'll see this:
Code:
C:\>Set first=2

C:\>set second=3

C:\>set /A sum=2 + 3
Sum is 5
You'll see that first and second have been replaced with their values in the Set /A line before the line is executed. This works, because their value was set on a previous line.
If you write that as all one line though, it won't work:
Code:
Set first=
Set second=
Set Sum=
(Set first=2)&(Set second=3)&(Set /A sum=%first% + %second%)&@Echo Sum is %Sum%
Produces this:
Code:
C:\>Set first=

C:\>Set second=

C:\>(Set first=2 )  & (Set second=3 )  & (Set /A sum= +  )  &
Missing operand.
Sum is
Variables are expanded before the line is executed, so when they are expanded for the Set /A statement, they haven't been assigned a value yet, as the line hasn't been executed. So an error is produced, and the numbers aren't added.
For this to work, you have to use delayed expansion:
Code:
SetLocal EnableDelayedExpansion
Set first=
Set second=
Set Sum=
(Set first=2)&(Set second=3)&(Set /A sum=first + second)&@Echo Sum is !Sum!
This works because first and second aren't replaced with their values until the Set /A command is executed, so they have been assigned values at that point.
Note that with Set /A, you don't need to use the ! symbol around the variables, expansion will be delayed automatically. You cannot use the % symbol though.

Keep in mind that a For loop, even if split across multiple lines, is still just one line (Same with a multi-line If statement), so without delayed expansion, the variables are replaced before the loop executes.
This code is actually only 3 lines, not 6:
Code:
Set _FileNumber=0
For /F "Tokens=*" %%I In ('dir /B') Do (
Set /A _FileNumber+=1
Echo File # %_FileNumber% is %%I
)
Echo Number of files is %_FileNumber% 
When the command processor gets to the For statement, it expands the variable in the Echo statement with it's current value, which is 0, so the line is actually this:
Code:
For /F "Tokens=*" %%I In ('dir /B') Do (
Set /A _FileNumber+=1
Echo File # 0 is %%I 
So it outputs 0 for each file found. It's still incremented, but it was already expanded for the Echo statement, so the chaning value will not be displayed.
Using Delayed Expansion and !_Filenumber!, the variable won't be expanded until the Echo statement is executed. The increment from the previous command will have been done, so it will display the proper number.
You do not need to use !_Filename! for the last statement, since it is outside the loop. It will use the value of _FileNumber after the For statement ends.

Jerry
__________________
Microsoft MVP - Windows Desktop Experience
Of course I know all the answers ; I just don't always match the answers to the right questions
Are you aware of the New Signature Limitations?
scrfix's Avatar
Computer Specs
Senior Member with 249 posts.
 
Join Date: May 2009
Experience: Computer Repair Expert
04-Jul-2009, 01:35 AM #3
Jerry,

Thank you for taking the time. I understand Delayed Expansion quite well I believe at this point and now I have a reference if I need to check it out again because I have questions.

Excellent psuedo as well. I followed most of it. I will have to reread it when I am more awake. 1:35am here.
__________________
Wayne Leiser, Spectacular Computer Repair Computer Repair, Computer Services
World Famous Gift Baskets: Gift Baskets, Corporate Gifts
Resources LLC: Water Treatment Coagulation, Water Recycling
Closed Thread Bookmark and Share

THIS THREAD HAS EXPIRED.
Are you having the same problem? We have volunteers ready to answer your question, but first you'll have to join for free. Need help getting started? Check out our Welcome Guide.

Smart Search

Find your solution!



Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
WELCOME TO TECH SUPPORT GUY! Are you looking for the solution to your computer problem? Join our site today to ask your question -- for free! Our site is run completely by volunteers who want to help you solve your computer problems. See our Welcome Guide to get started.

Thread Tools


You Are Using:
Server ID
Advertisements do not imply our endorsement of that product or service.
All times are GMT -5. The time now is 08:01 AM.
Copyright © 1996 - 2009 TechGuy, Inc. All rights reserved.
Powered by vBulletin, Copyright © 2000 - 2009, Jelsoft Enterprises Ltd.
Powered by Cermak Technologies, Inc.