1

I have 2 strings:

answer="spaghetti"
guess="spgheti"

I would like to know if there was some way to count the amount of letters in $answer that are same as $guess, in this case I should get number 7. Some notes are that $answer and $guess will change.'

Because of the accusation that I posted a duplicate, the one suggested is asking for length of word; I am asking for how many letters in 2 strings are equal. For example, "Stackoverflow" and "stkflw". would want something to count how many letters in "stkflw" are equal to the letters in "Stackoverflow". I need it to count all letters in a word, for an example, "Test" should return 4 because it has 4 letters (an answer has one that returns 3 with test which is not desirable)

If this could be done in bash, that would be great! :)

  • am sorry, I completely misread the question... – Sundeep Mar 4 '17 at 3:58
  • It's okay, i likely phrased it all backwards. :) – Lee Ikard Mar 4 '17 at 4:00
  • 1
    @LeeIkard can you add more examples, like for fete and feet, good and goodness, par and rap, etc – Sundeep Mar 4 '17 at 4:04
  • A bash version is preferred. – Lee Ikard Mar 5 '17 at 21:56
  • @Sundeep I didn't include a bunch of exmaples because they will always vary as a random word will be chosen as an answer (and the guess will always vary. That's the reason the code in the question is set as a variable, not string) – Lee Ikard Mar 5 '17 at 21:58
1
answer=spaghetti
guess=aeghipstt

# find the individual letters in the answer
# use an associative array to manage duplicates
declare -A letters=()
for ((i=0; i < ${#answer}; i++)); do
    letters[${answer:i:1}]=1
done

# remove duplicate letters in the guess.
# could use the above technique, but here's another one
guess_uniq=$( sed 's/./&\n/g' <<< "$guess" | sort -u | tr -d '\n' )

# loop over the unique letters of the guess, 
# and count how many letters are in the answer
matches=0
for ((i=0; i < ${#guess_uniq}; i++)); do
    [[ ${letters[${guess_uniq:i:1}]} = "1" ]] && (( matches++ ))
done

if (( matches == ${#guess_uniq} )); then echo "Correct"; fi
  • returns "Correct" on every guess. – Lee Ikard Mar 5 '17 at 21:53
  • if that is meant as a bug report, I need more info – glenn jackman Mar 5 '17 at 22:15
  • I use any answer and any guess, and it returns "correct" every time. – Lee Ikard Mar 6 '17 at 3:03
  • I see that it says Correct for any guess that only contains letters from the answer, even if it does not contain all the letters in answer – glenn jackman Mar 6 '17 at 3:10
  • Oh, nevermind, i was wrong. But this doesn't exactly answer my question because it returns correct instead of a number. – Lee Ikard Mar 6 '17 at 5:03
2

In Perl, the transliteration operator tr// (which works pretty much like the tr shell utility) will return the number of characters that were transliterated.

$ perl -e 'print("spgheti" =~ tr/spaghetti/spaghetti/, "\n")'
7

I.e. "seven characters in spgheti are found in spaghetti".

$ perl -e 'print("spaghetti" =~ tr/spgheti/spgheti/, "\n")'
8

I.e. "eight characters in spaghetti are found in spgheti" (since t occurs twice in spaghetti, it is counted twice).

Putting a loop around it:

while read word1 word2; do
  perl -e 'printf("%s / %s: %d\n", $ARGV[0], $ARGV[1],
    eval "$ARGV[0] =~ tr/$ARGV[1]/$ARGV[1]/")' "$word1" "$word2"
done <<LIST_END
stkflw Stackoverflow
fete feet
good goodness
par rap
LIST_END

The Perl eval() call in necessary to be able to insert $ARGV[1] into the search and replacement list of tr//.

Output:

stkflw / Stackoverflow: 5
fete / feet: 4
good / goodness: 4
par / rap: 3

Or, reading from a file with two words on each line:

while read word1 word2; do
  # as before
done <wordpairs
  • Works well, it counts all letters, and returns me the number. However, this is in perl, I would like it in bash. I will use this answer in my project until a bash version comes along (that counts all letters, even repeating ones) – Lee Ikard Mar 5 '17 at 21:55
2

Here's how to do it in bash.

# ----------------------------------------------------------------------------
# INPUT:
# $1 answer (contains the "source" string)
# $2 guess (contains individual characters to be counted from $answer)
#
# OUTPUT:
# prints to standard output a count of the characters from 'guess' which
# appear in 'answer'
# ----------------------------------------------------------------------------
answer=$1
guess=$2
count=0

# for each character in $guess, observe whether its elimination from
# $answer causes the resultant string to be different; if so, it exists,
# therefore increment a counter

# iterate over the characters of $guess
for (( i=0; i < ${#guess}; i=i+1 )); do
    current_char=${guess:$i:1}

    # attempt to extract current character
    answer_after_extract=${answer//$current_char}

    # has $answer changed?
    if [[ $answer_after_extract != $answer ]]; then
        count=$(( count + 1 ))
    fi
    answer=$answer_after_extract
done

echo $count

SAMPLE OUTPUT

$ ./answer spaghetti spgheti
7

$ ./answer abcdefghijklmnopqrstuvwxyz aeiou
5

$ ./answer abcdefghijklmnopqrstuvwxyz xyzzy
3
  • Tried with "test" and "test" and it gave me 3, i would like to have it return 4 since there are 2 T's in test (and other words might have repeating letters) – Lee Ikard Mar 5 '17 at 21:52
  • Ok, no problem. My original script counted only "distinct" (non-repeating) characters from the "guess". One simple change will count all characters, namely: replacing the two forward-slashes with a single forward slash on line 25: answer_after_extract=${answer/$current_char} – jasontmassey Mar 7 '17 at 0:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.