Vicky
Vicky

Reputation: 1328

How to tell if two strings of any length are anagrams using bash, awk or any using command or script?

The string or word can be of any length.

Eg "William Shakespeare" = "I am a weakish speller" both are anagrams

E.g. "Madam Curie" = "Radium came"

Upvotes: 2

Views: 1818

Answers (6)

RARE Kpop Manifesto
RARE Kpop Manifesto

Reputation: 2807

don't waste time sorting the characters in the string. Just sequentially count frequencies of them, and compare. An anagram, by definition, would cancel out each other's buckets perfectly.

Upvotes: 0

Vijay S B
Vijay S B

Reputation: 1315

Sort characters in strings and compare irrespective of case.

str1="$1"
str2="$2"

sorted1=$(echo $str1 | grep -o . | sort | tr -d "\n")
sorted2=$(echo $str2 | grep -o . | sort | tr -d "\n")

if [[ $(typeset -l $sorted1) == $(typeset -l $sorted2) ]]
then
    echo "Strings are anagrams"
else
    echo "Strings are not anagrams"
fi

Upvotes: 0

Surepic 342
Surepic 342

Reputation: 67

#!/bin/bash

#set -x

i=0
for letter in {A..Z}
do
alphabet[$i]="$letter"
((i++))
done

i=0
for digits in {0..25}
do
array[$i]=0
((i++))
done

read -p "Enter first word: " word1
read -p "Enter second word: " word2

while read -n 1 letter
do

if [ -z "$letter" ]
then continue
fi
for b in "${!alphabet[@]}"
do
if [ "$letter" = "${alphabet[$b]}" ]
then
((array[$b]+=1))
break
fi
done
done < <(echo "${word1^^}")

while read -n 1 letter
do
if [ -z "$letter" ]
then continue
fi
for b in "${!alphabet[@]}"
do
if [ "$letter" = "${alphabet[$b]}" ]
then
((array[$b]-=1))
break
fi
done
done < <(echo "${word2^^}")

echo -n "Words are "
for element in "${array[@]}"
do
if [ "$element" -ne 0 ]
then echo -n "not "
fi
done

echo "anagrams"

echo
exit

And in functions

#!/bin/bash

set -x

i=0
for letter in {A..Z}
do
alphabet[$i]="$letter"
((i++))
done


read_word(){
local array=()
local i=0
for digits in {0..25}
do
array[$i]=0
((i++))
done
local sentence="$1"
while read -n 1 letter
do
if [ -z "$letter" ]
then continue
fi
for b in "${!alphabet[@]}"
do 
if [ "$letter" = "${alphabet[$b]}" ]
then
((array[$b]+=1))
break
fi
done
done < <(echo "${sentence^^}")
echo "${array[@]}"
}
 
equal_array(){
if [ "$1" = "$2" ]
then echo "anagrams"
else echo " not anagrams"
fi
}
 
read -p "Enter first word: " word1
read -p "Enter second word: " word2

word1=($(read_word "$word1"))
word2=($(read_word "$word2"))

equal_array "${word1[*]}" "${word2[*]}"

exit


Upvotes: 0

Kent
Kent

Reputation: 195029

an awk solution looks not so compact like others, but slightly different:

awk -v s1="William Shakespeare" -v s2="I am a weakish speller" '    
function chkTxt(s) {
    split(tolower(s), arr, //)
    asort(arr)
    result=""
    for(i=1;i<=length(arr);i++)
        result = result""arr[i]
    return result
}

BEGIN{
    x=gsub(/[[:blank:]]/,"",s1)
    y=gsub(/[[:blank:]]/,"",s2)

    if (x+y==0 || (x&&y)) {
        print chkTxt(s1)==chkTxt(s2)? "True":"False"
        exit
    }
    print "False"
}'

here you pass the two string variable to s1 and s2.

Note For space/blank checking, I noticed that your example doesn't restrict the count of the spaces, however, it seems that if there were spaces, two strings must have at least one spaces. Like foo bar and f o o ba r are anagrams. However foobar and barf o o are not.

The above codes do the check.

Upvotes: 0

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

Easy with Python:

anagram.py script:

import sys

s1 = sys.argv[1]
s2 = sys.argv[2]
fmt = '"{:s}" and "{:s}" are{:s} anargams'

if sorted(s1.lower().translate(None,' \n\r\t')) == sorted(s2.lower().translate(None,' \n\r\t')):
    print(fmt.format(s1, s2, ''))
else:
    print(fmt.format(s1, s2, ' NOT'))

Usage:

python anagrams.py "William Shakespeare" "I am a weakish speller"

The output:

"William Shakespeare" and "I am a weakish speller" are anargams

python anagrams.py "William Shakespeare" "William Hopkins"

The output:

"William Shakespeare" and "William Hopkins" are NOT anargams

Upvotes: 1

anubhava
anubhava

Reputation: 784918

This may work for you:

# function to cleanup a given argument by doing this:
# 1. Remove all alphanumerics
# 2. Convert to all lowercasing all characters 
# 3. Sorting all characters
# 4. Stripping all newlines 
prep() {
   fold -w1 <<< "${1//[^[:alnum:]]/}" | tr '[:upper:]' '[:lower:]' | sort | tr -d '\n'
}

# function to check if given 2 arguments are anagrams
isAnagram() {
   a=$(prep "$1")
   b=$(prep "$2")
   [[ $a = $b ]] && echo "yes" || echo "no";
}

To call them use:

isAnagram "William Shakespeare" "I am a weakish speller"
yes

isAnagram "Madam Curie" "Radium came"
yes

isAnagram "cat" "act"
yes

isAnagram "cat" "cot"
no

Upvotes: 4

Related Questions