How to Create an Anagram Checker in Batch Script
This tutorial walks you through building an anagram checker natively in a Windows Batch Script. Working with string manipulation and character counting directly in the Command Prompt is an excellent way to master dynamic variable structures and nested FOR loop evaluation without relying on high-level programming environments.
An anagram is a word or phrase formed by completely rearranging the letters of another word or phrase, using all the original letters exactly once (e.g., "LISTEN" and "SILENT"). By the end of this guide, you will have a script that takes two user inputs, sanitizes them, counts their character frequencies, and compares the results to determine whether they are perfect anagrams.
The Logic Behind Anagram Verification
Batch has no native array-sorting commands (like Python's sorted() or JavaScript's split().sort().join()), so the most reliable approach is character frequency counting.
If Word A contains exactly one L, one I, one S, one T, one E, and one N, and Word B has the same identical count for every letter, the two words are guaranteed to be anagrams.
Building Frequency Arrays
We simulate associative arrays using dynamically named variables. For each word, we iterate through every character and increment a counter variable named after that character.
@echo off
setlocal enabledelayedexpansion
set "WORD_A=LISTEN"
set "WORD_B=SILENT"
:: After counting (shown conceptually):
:: Word A counts
set "countA_L=1" & set "countA_I=1" & set "countA_S=1"
set "countA_T=1" & set "countA_E=1" & set "countA_N=1"
:: Word B counts
set "countB_S=1" & set "countB_I=1" & set "countB_L=1"
set "countB_E=1" & set "countB_N=1" & set "countB_T=1"
When we compare !countA_L! with !countB_L! (and so on for every letter), the script confirms equality across the board.
Preparing the String for Evaluation
A robust script must format user input before evaluation. Anagram checks are case-insensitive and conventionally ignore spaces, so input must be converted to a uniform case and stripped of whitespace.
The Wrong Way: Direct Raw Comparison
Skipping sanitization and jumping straight into a string comparison will fail almost every time.
Wrong Code Example:
@echo off
set "W1=Dormitory"
set "W2= dirty room"
:: Fails because spaces and letter casing are not accounted for
if "%W1%"=="%W2%" (
echo These are anagrams!
) else (
echo Not anagrams.
)
What Happens:
The string Dormitory does not match dirty room. The script compares raw characters byte-for-byte, completely missing the anagram relationship due to case differences and embedded spaces.
The Correct Way: Sanitize First
Remove all spaces and convert every lowercase letter to its uppercase equivalent.
Correct Code Example:
@echo off
setlocal enabledelayedexpansion
set "INPUT= Dirty Room "
:: 1. Remove all spaces
set "CLEAN=!INPUT: =!"
:: 2. Convert lowercase to uppercase
for %%L 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 (
:: Build the uppercase version of %%L
for /f "tokens=1 delims=" %%U in ('echo %%L ^| cmd /e /c "for /f %%a in ('more') do @echo %%a"') do (
rem - simpler: just list pairs explicitly
)
)
:: The reliable method: explicit lowercase-to-uppercase replacement
for %%P in (
"a=A" "b=B" "c=C" "d=D" "e=E" "f=F" "g=G"
"h=H" "i=I" "j=J" "k=K" "l=L" "m=M" "n=N"
"o=O" "p=P" "q=Q" "r=R" "s=S" "t=T" "u=U"
"v=V" "w=W" "x=X" "y=Y" "z=Z"
) do set "CLEAN=!CLEAN:%%~P!"
echo Sanitized: !CLEAN!
What Happens:
The variable becomes DIRTYROOM. Now it is ready for character frequency counting, and differences in case or spacing will not cause a false mismatch.
Full Script Implementation
Below is the complete, corrected anagram checker. It sanitizes both inputs, counts every letter's frequency using dynamically named variables, and compares the two frequency sets.
@echo off
setlocal enabledelayedexpansion
title Universal Anagram Checker
:PROMPT
cls
color
echo ========================================================
echo TERMINAL ANAGRAM CHECKER
echo ========================================================
echo.
set "WORD_A="
set "WORD_B="
set /p "WORD_A=Enter First String: "
if not defined WORD_A goto PROMPT
set /p "WORD_B=Enter Second String: "
if not defined WORD_B goto PROMPT
:: -------------------------------------------------------
:: 1. SANITIZE - remove spaces, convert to uppercase
:: -------------------------------------------------------
set "SAN_A=!WORD_A: =!"
set "SAN_B=!WORD_B: =!"
for %%P in (
"a=A" "b=B" "c=C" "d=D" "e=E" "f=F" "g=G"
"h=H" "i=I" "j=J" "k=K" "l=L" "m=M" "n=N"
"o=O" "p=P" "q=Q" "r=R" "s=S" "t=T" "u=U"
"v=V" "w=W" "x=X" "y=Y" "z=Z"
) do (
set "SAN_A=!SAN_A:%%~P!"
set "SAN_B=!SAN_B:%%~P!"
)
:: -------------------------------------------------------
:: 2. QUICK LENGTH CHECK - different lengths cannot match
:: -------------------------------------------------------
set "tmpA=!SAN_A!"
set "lenA=0"
:LEN_A
if defined tmpA (
set "tmpA=!tmpA:~1!"
set /a "lenA+=1"
goto LEN_A
)
set "tmpB=!SAN_B!"
set "lenB=0"
:LEN_B
if defined tmpB (
set "tmpB=!tmpB:~1!"
set /a "lenB+=1"
goto LEN_B
)
if not "!lenA!"=="!lenB!" (
color 0C
echo.
echo [NO MATCH] Different lengths ^(!lenA! vs !lenB!^). Not anagrams.
echo.
pause
goto PROMPT
)
:: -------------------------------------------------------
:: 3. INITIALIZE frequency counters for A-Z
:: -------------------------------------------------------
for %%C 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 "cntA_%%C=0"
set "cntB_%%C=0"
)
:: -------------------------------------------------------
:: 4. COUNT characters in SAN_A
:: -------------------------------------------------------
set "idx=0"
:COUNT_A
set "ch=!SAN_A:~%idx%,1!"
if "!ch!"=="" goto COUNT_B_INIT
set /a "cntA_!ch!+=1"
set /a "idx+=1"
goto COUNT_A
:: -------------------------------------------------------
:: 5. COUNT characters in SAN_B
:: -------------------------------------------------------
:COUNT_B_INIT
set "idx=0"
:COUNT_B
set "ch=!SAN_B:~%idx%,1!"
if "!ch!"=="" goto COMPARE
set /a "cntB_!ch!+=1"
set /a "idx+=1"
goto COUNT_B
:: -------------------------------------------------------
:: 6. COMPARE frequency arrays
:: -------------------------------------------------------
:COMPARE
set "IS_ANAGRAM=TRUE"
for %%C 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 (
if not "!cntA_%%C!"=="!cntB_%%C!" (
set "IS_ANAGRAM=FALSE"
)
)
echo.
if "!IS_ANAGRAM!"=="TRUE" (
color 0A
echo [MATCH] "!WORD_A!" and "!WORD_B!" ARE anagrams.
) else (
color 0C
echo [NO MATCH] "!WORD_A!" and "!WORD_B!" are NOT anagrams.
)
echo.
pause
goto PROMPT
What Changed from the Original
| Issue | Original Code | Fixed Code |
|---|---|---|
| Uppercase conversion did nothing | set "SAN_A=!SAN_A:%%C=%%C!" replaces A with A, B with B, a no-op that never converts lowercase letters. | Uses "a=A" through "z=Z" substitution pairs so every lowercase letter is explicitly replaced with its uppercase counterpart. |
| Character extraction in counting loops | Used call set "char_A=%%SAN_A:~!iter_A!,1%%" with a separate iterator variable. The call + double-percent trick works but is fragile and slower. | Uses !SAN_A:~%idx%,1!, the outer %idx% is expanded by the goto loop re-parse, and the inner !SAN_A:~...! is expanded by delayed expansion. No call needed. |
| No length pre-check | Jumps straight into counting even when the strings are obviously different lengths. | Adds a quick length comparison that exits early, saving unnecessary work. |
| Variable naming clarity | Mixed naming (count_A_, count_B_, char_A, iter_A) was inconsistent. | Consistent cntA_, cntB_, ch, idx naming throughout. |
How It Works Step by Step
- Input: The user types two strings.
- Sanitize: Spaces are stripped with
!VAR: =!. Lowercase letters are replaced with uppercase equivalents using 26 explicit substitution pairs. - Length check: If the sanitized strings differ in length, they cannot be anagrams, so the script reports a mismatch immediately.
- Frequency counting: Two
gotoloops walk through each sanitized string one character at a time. For each character (e.g.,T), the corresponding counter variable (cntA_TorcntB_T) is incremented withset /a. - Comparison: A
FORloop iterates over every letter A–Z and checks whethercntA_%%CequalscntB_%%C. Any mismatch setsIS_ANAGRAMtoFALSE. - Result: The script prints a color-coded match or mismatch message, then loops back for another pair of inputs.
Example Runs
Enter First String: Listen
Enter Second String: Silent
[MATCH] "Listen" and "Silent" ARE anagrams.
Enter First String: Dormitory
Enter Second String: Dirty Room
[MATCH] "Dormitory" and "Dirty Room" ARE anagrams.
Enter First String: Hello
Enter Second String: World
[NO MATCH] "Hello" and "World" are NOT anagrams.
Enter First String: Hello
Enter Second String: Goodbye
[NO MATCH] Different lengths (5 vs 7). Not anagrams.
This script handles alphabetical characters (A–Z) only. Inputs containing digits, punctuation, or shell metacharacters (&, |, <, >, ^, !) may produce incorrect results or parsing errors. For a production tool, add input validation using findstr to reject non-alphabetical characters before processing:
echo !SAN_A! | findstr /r "[^A-Z]" >nul && (
echo ERROR: Non-alphabetical characters detected.
pause
goto PROMPT
)
Conclusion
Building an anagram checker in pure Batch Script requires constructing frequency counters out of dynamically named variables and carefully iterating through strings one character at a time. The key pitfalls are forgetting to actually convert lowercase to uppercase (a substitution of A with A does nothing) and handling the quirks of delayed expansion inside goto loops. With proper sanitization and a systematic count-and-compare approach, the Command Prompt is more than capable of solving this classic string problem.undefined