2

I have the following code and results, and I cannot work out why the capitalization of the first letter is not holding.

Code

 @echo off
    set /P "PrimaryApplicantFirst=Enter First Name: "
    call :toUpperFirst %PrimaryApplicantFirst%
    echo %PrimaryApplicantFirst%
    pause

------------------------------------------------------------------------
:toUpperFirst str
    SETLOCAL ENABLEDELAYEDEXPANSION
    set "name=%~1" 

set first_letter=%name:~0,1%
set last_letters=%name:~1%



for %%# in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do (
    set first_letter=!first_letter:%%#=%%#!
)

set "PrimaryApplicantFirst=%first_letter%%last_letters%"
echo %PrimaryApplicantFirst%

SETLOCAL DISABLEDELAYEDEXPANSION
EXIT /b

Inputting "test" will result in

Test
test

Why is this the case?

EDIT - The following also produces the error. Am I missing something?

:toUpperFirst var
setlocal enableDelayedExpansion
set "name=!%~1!"

set first_letter=%name:~0,1%
set last_letters=%name:~1%

for %%# in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do (
    set first_letter=!first_letter:%%#=%%#!
)

set "PrimaryApplicantFirst=%first_letter%%last_letters%"

endlocal && (
    set "%~1=%PrimaryApplicantFirst%"
)
exit /b %errorlevel%
Joshua Patterson
  • 433
  • 1
  • 4
  • 15
  • 1
    `SETLOCAL DISABLEDELAYEDEXPANSION` -> `endlocal & set "PrimaryApplicantFirst=%PrimaryApplicantFirst%"` – user4003407 Feb 25 '16 at 06:39
  • Because of the `setlocal` scope.You need to use `endlocal` and set variable value at the same time which can be achieved with `&` like in the PetSerAl comment. Check your [question](http://stackoverflow.com/a/35593694/388389) and the answer for more details. – npocmaka Feb 25 '16 at 06:45
  • 1
    @JoshuaPatterson Your updated version work fine for me. Hope, do not forgot update `call` instruction as well. – user4003407 Feb 25 '16 at 07:00

2 Answers2

0

In honesty, im still trying to convince myself as to how it works. I understand that the issue lies in how the for loop behaves and i would like to believe that variables are not being updated because its not being specified to update. I want to say that the for-loops are ran like a hypothetical situation which should not specifically record values since its a role-play of logic. Hence when you type SETLOCAL ENABLEDELAYEDEXPANSION right at the beginning of your code instead of when its being called, the problem is corrected.

This solution came about when i was writing alternative code for yours, which one of my ideas involved arrays.. (A more indepth version can be veiwed here.). These links detail information about the "DelayedExpansion" variable and are the grounds of my hypothesis for this situation. Whether or not you want delayed expansion in your final code is up to you. Here is the corrected code just for quick copy.

 @echo off
SETLOCAL ENABLEDELAYEDEXPANSION
    set /P "PrimaryApplicantFirst=Enter First Name: "
    call :toUpperFirst %PrimaryApplicantFirst%
    echo %PrimaryApplicantFirst%
    pause

------------------------------------------------------------------------
:toUpperFirst str
    set "name=%~1" 

set first_letter=%name:~0,1%
set last_letters=%name:~1%



for %%# in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do (
    set first_letter=!first_letter:%%#=%%#!
)

set "PrimaryApplicantFirst=%first_letter%%last_letters%"
echo %PrimaryApplicantFirst%

SETLOCAL DISABLEDELAYEDEXPANSION
EXIT /b

As you can see, much of the code is left unchanged disregarding the second line the delayed expansion during the run. Why the change of location of the ENABLEDELAYEDEXPANSION is probably because that when you were calling other parts of your code, you were asking for it to run the delayed expansion internally as opposed to externally so the variables inside could not get passed outside

Community
  • 1
  • 1
Jouster500
  • 762
  • 12
  • 25
0
:toUpperFirst str
    SETLOCAL ENABLEDELAYEDEXPANSION
    set "name=%~1" 

set first_letter=%name:~0,1%
set last_letters=%name:~1%
for %%# in (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) do (
    set first_letter=!first_letter:%%#=%%#!
)

set "PrimaryApplicantFirst=%first_letter%%last_letters%"
echo %PrimaryApplicantFirst%

ENDLOCAL&SET "PrimaryApplicantFirst=%PrimaryApplicantFirst%"
EXIT /b

Sadly, setlocal is not a switch - it invokes a new environment which inherits the settings of the existing environment, modified by any parameters to the setlocal command.

When and exit is executed or physical end-of-file is reached, an implicit endlocal is applied to an open in-context local environment, the new evnvironment is closed and the original restored.

The endlocal%set "var=%var%" structure uses a parsing trick. When the line is parsed, the value of any %var% is substituted for %var% and then the line is executed, hence what is actually executed is endlocal&set "var=thecurrentvalueofvar"

Magoo
  • 77,302
  • 8
  • 62
  • 84