Determine if a string has all unique characters

From Rosetta Code
Task
Determine if a string has all unique characters
You are encouraged to solve this task according to the task description, using any language you may know.
Task

Given a character string   (which may be empty, or have a length of zero characters):

  •   create a function/procedure/routine to:
  •   determine if all the characters in the string are unique
  •   indicate if or which character is duplicated and where
  •   display each string and its length   (as the strings are being examined)
  •   a zero─length (empty) string shall be considered as unique
  •   process the strings from left─to─right
  •   if       unique,   display a message saying such
  •   if not unique,   then:
  •   display a message saying such
  •   display what character is duplicated
  •   only the 1st non─unique character need be displayed
  •   display where "both" duplicated characters are in the string
  •   the above messages can be part of a single message
  •   display the hexadecimal value of the duplicated character


Use (at least) these five test values   (strings):

  •   a string of length     0   (an empty string)
  •   a string of length     1   which is a single period   (.)
  •   a string of length     6   which contains:   abcABC
  •   a string of length     7   which contains a blank in the middle:   XYZ  ZYX
  •   a string of length   36   which   doesn't   contain the letter "oh":
1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ


Show all output here on this page.

Other tasks related to string operations:
Metrics
Counting
Remove/replace
Anagrams/Derangements/shuffling
Find/Search/Determine
Formatting
Song lyrics/poems/Mad Libs/phrases
Tokenize
Sequences



11l

Translation of: Kotlin
F processString(input)
   [Char = Int] charMap
   V dup = Char("\0")
   V index = 0
   V pos1 = -1
   V pos2 = -1
   L(key) input
      index++
      I key C charMap
         dup = key
         pos1 = charMap[key]
         pos2 = index
         L.break
      charMap[key] = index
   V unique = I dup == Char("\0") {‘yes’} E ‘no’
   V diff = I dup == Char("\0") {‘’} E ‘'’dup‘'’
   V hexs = I dup == Char("\0") {‘’} E hex(dup.code)
   V position = I dup == Char("\0") {‘’} E pos1‘ ’pos2
   print(‘#<40  #<6  #<10  #<8  #<3  #<5’.format(input, input.len, unique, diff, hexs, position))

print(‘#<40  #2  #10  #8  #.  #.’.format(‘String’, ‘Length’, ‘All Unique’, ‘1st Diff’, ‘Hex’, ‘Positions’))
print(‘#<40  #2  #10  #8  #.  #.’.format(‘------------------------’, ‘------’, ‘----------’, ‘--------’, ‘---’, ‘---------’))
L(s) [‘’, ‘.’, ‘abcABC’, ‘XYZ ZYX’, ‘1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ’]
   processString(s)
Output:
String                                    Length  All Unique  1st Diff  Hex  Positions
------------------------                  ------  ----------  --------  ---  ---------
                                          0       yes                             
.                                         1       yes                             
abcABC                                    6       yes                             
XYZ ZYX                                   7       no          'Z'       5A   3 5  
1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ      36      no          '0'       30   10 25

Action!

PROC PrintBH(BYTE a)
  BYTE ARRAY hex=['0 '1 '2 '3 '4 '5 '6 '7 '8 '9 'A 'B 'C 'D 'E 'F]

  Put(hex(a RSH 4))
  Put(hex(a&$0F))
RETURN

PROC Test(CHAR ARRAY s)
  BYTE i,j,n,pos1,pos2

  pos1=0 pos2=0
  n=s(0)-1
  IF n=255 THEN n=0 FI
  FOR i=1 TO n
  DO
    FOR j=i+1 TO s(0)
    DO
      IF s(j)=s(i) THEN
        pos1=i
        pos2=j
        EXIT
      FI
    OD
    IF pos1#0 THEN
      EXIT
    FI
  OD

  PrintF("""%S"" (len=%B) -> ",s,s(0))
  IF pos1=0 THEN
    PrintE("all characters are unique.")
  ELSE
    PrintF("""%C"" (hex=$",s(pos1))
    PrintBH(s(pos1))
    PrintF(") is duplicated at pos. %B and %B.%E",pos1,pos2)
  FI
  PutE()
RETURN

PROC Main()
  Test("")
  Test(".")
  Test("abcABC")
  Test("XYZ ZYX")
  Test("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ")
RETURN
Output:

Screenshot from Atari 8-bit computer

"" (len=0) -> all characters are unique.

"." (len=1) -> all characters are unique.

"abcABC" (len=6) -> all characters are unique.

"XYZ ZYX" (len=7) -> "X" (hex=$58) is duplicated at pos. 1 and 7.

"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (len=36) -> "0" (hex=$30) is duplicated at pos. 10 and 25.

Ada

with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Text_IO; use Ada.Text_IO;
procedure Test_All_Chars_Unique is
   procedure All_Chars_Unique (S : in String) is
   begin
      Put_Line ("Input = """ & S & """, length =" & S'Length'Image);
      for I in S'First .. S'Last - 1 loop
         for J in I + 1 .. S'Last loop
            if S(I) = S(J) then
               Put (" First duplicate at positions" & I'Image &
                    " and" & J'Image & ", character = '" & S(I) &
                    "', hex = ");
               Put (Character'Pos (S(I)), Width => 0, Base => 16);
               New_Line;
               return;
            end if;
         end loop;
      end loop;
      Put_Line (" All characters are unique.");
   end All_Chars_Unique;
begin
   All_Chars_Unique ("");
   All_Chars_Unique (".");
   All_Chars_Unique ("abcABC");
   All_Chars_Unique ("XYZ ZYX");
   All_Chars_Unique ("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ");
end Test_All_Chars_Unique;
Output:
Input = "", length = 0
 All characters are unique.
Input = ".", length = 1
 All characters are unique.
Input = "abcABC", length = 6
 All characters are unique.
Input = "XYZ ZYX", length = 7
 First duplicate at positions 1 and 7, character = 'X', hex = 16#58#
Input = "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ", length = 36
 First duplicate at positions 10 and 25, character = '0', hex = 16#30#

ALGOL 68

BEGIN
    # mode to hold the positions of duplicate characters in a string      #
    MODE DUPLICATE = STRUCT( INT original, first duplicate ); 
    # finds the first non-unique character in s and returns its position  #
    # and the position of the original character in a DUPLICATE           #
    # if all characters in s are uniue, returns LWB s - 1, UPB s + 1      #
    PROC first duplicate position = ( STRING s )DUPLICATE:
    BEGIN
        BOOL all unique := TRUE;
        INT  o pos      := LWB s - 1;
        INT  d pos      := UPB s + 1;
        FOR i FROM LWB s TO UPB s WHILE all unique DO
            FOR j FROM i + 1 TO UPB s WHILE all unique DO
                IF NOT ( all unique := s[ i ] /= s[ j ] ) THEN
                    o pos := i;
                    d pos := j
                FI
            OD
        OD;
        DUPLICATE( o pos, d pos )
    END # first duplicate position # ;
    # task test cases                                                     #
    []STRING tests = ( "", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" );
    FOR t pos FROM LWB tests TO UPB tests DO
        IF  STRING s    = tests[ t pos ];
            DUPLICATE d = first duplicate position( s );
            print( ( "<<<", s, ">>> (length ", whole( ( UPB s + 1 ) - LWB s, 0 ), "): " ) );
            original OF d < LWB s
        THEN
            print( ( " all characters are unique", newline ) )
        ELSE
            # have at least one duplicate #
            print( ( " first duplicate character: """, s[ original OF d ], """"
                   , " at: ", whole( original OF d, 0 ), " and ", whole( first duplicate OF d, 0 )
                   , newline
                   )
                 )
        FI
    OD
END
Output:
<<<>>> (length 0):  all characters are unique
<<<.>>> (length 1):  all characters are unique
<<<abcABC>>> (length 6):  all characters are unique
<<<XYZ ZYX>>> (length 7):  first duplicate character: "X" at: 1 and 7
<<<1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ>>> (length 36):  first duplicate character: "0" at: 10 and 25

AppleScript

Following AppleScript's convention of one-based indices:

Translation of: Haskell
Translation of: Python
Translation of: JavaScript
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

on run
    script showSource
        on |λ|(s)
            quoted("'", s) & " (" & length of s & ")"
        end |λ|
    end script
    
    script showDuplicate
        on |λ|(mb)
            script go
                on |λ|(tpl)
                    set {c, ixs} to tpl
                    quoted("'", c) & " at " & intercalate(", ", ixs)
                end |λ|
            end script
            maybe("None", go, mb)
        end |λ|
    end script
    
    fTable("Indices (1-based) of any duplicated characters:\n", ¬
        showSource, showDuplicate, ¬
        duplicatedCharIndices, ¬
        {"", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"})
end run


------------------CHARACTER DUPLICATIONS-------------------

-- duplicatedCharIndices :: String -> Maybe (Char, [Int])
on duplicatedCharIndices(s)
    script positionRecord
        on |λ|(dct, c, i)
            set k to (id of c) as string
            script additional
                on |λ|(xs)
                    insertDict(k, xs & i, dct)
                end |λ|
            end script
            maybe(insertDict(k, {i}, dct), additional, lookupDict(k, dct))
        end |λ|
    end script
    
    script firstDuplication
        on |λ|(sofar, idxs)
            set {iCode, xs} to idxs
            if 1 < length of xs then
                script earliest
                    on |λ|(kxs)
                        if item 1 of xs < (item 1 of (item 2 of kxs)) then
                            Just({chr(iCode), xs})
                        else
                            sofar
                        end if
                    end |λ|
                end script
                maybe(Just({chr(iCode), xs}), earliest, sofar)
            else
                sofar
            end if
        end |λ|
    end script
    
    foldl(firstDuplication, Nothing(), ¬
        assocs(foldl(positionRecord, {name:""}, chars(s))))
end duplicatedCharIndices


--------------------------GENERIC--------------------------

-- Just :: a -> Maybe a
on Just(x)
    -- Constructor for an inhabited Maybe (option type) value.
    -- Wrapper containing the result of a computation.
    {type:"Maybe", Nothing:false, Just:x}
end Just

-- Nothing :: Maybe a
on Nothing()
    -- Constructor for an empty Maybe (option type) value.
    -- Empty wrapper returned where a computation is not possible.
    {type:"Maybe", Nothing:true}
end Nothing

-- Tuple (,) :: a -> b -> (a, b)
on Tuple(a, b)
    -- Constructor for a pair of values, possibly of two different types.
    {type:"Tuple", |1|:a, |2|:b, length:2}
end Tuple

-- assocs :: Map k a -> [(k, a)]
on assocs(m)
    script go
        on |λ|(k)
            set mb to lookupDict(k, m)
            if true = |Nothing| of mb then
                {}
            else
                {{k, |Just| of mb}}
            end if
        end |λ|
    end script
    concatMap(go, keys(m))
end assocs

-- keys :: Dict -> [String]
on keys(rec)
    (current application's ¬
        NSDictionary's dictionaryWithDictionary:rec)'s allKeys() as list
end keys

-- chr :: Int -> Char
on chr(n)
    character id n
end chr

-- chars :: String -> [Char]
on chars(s)
    characters of s
end chars

-- compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
on compose(f, g)
    script
        property mf : mReturn(f)
        property mg : mReturn(g)
        on |λ|(x)
            mf's |λ|(mg's |λ|(x))
        end |λ|
    end script
end compose

-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
    set lng to length of xs
    set acc to {}
    tell mReturn(f)
        repeat with i from 1 to lng
            set acc to acc & (|λ|(item i of xs, i, xs))
        end repeat
    end tell
    return acc
end concatMap

-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m, n)
    if m  n then
        set lst to {}
        repeat with i from m to n
            set end of lst to i
        end repeat
        lst
    else
        {}
    end if
end enumFromTo

-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl

-- fst :: (a, b) -> a
on fst(tpl)
    if class of tpl is record then
        |1| of tpl
    else
        item 1 of tpl
    end if
end fst

-- fTable :: String -> (a -> String) -> (b -> String) -> (a -> b) -> [a] -> String
on fTable(s, xShow, fxShow, f, xs)
    set ys to map(xShow, xs)
    set w to maximum(map(my |length|, ys))
    script arrowed
        on |λ|(a, b)
            justifyRight(w, space, a) & " -> " & b
        end |λ|
    end script
    s & linefeed & unlines(zipWith(arrowed, ¬
        ys, map(compose(fxShow, f), xs)))
end fTable

-- insertDict :: String -> a -> Dict -> Dict
on insertDict(k, v, rec)
    tell current application
        tell dictionaryWithDictionary_(rec) of its NSMutableDictionary
            its setValue:v forKey:(k as string)
            it as record
        end tell
    end tell
end insertDict

-- intercalate :: String -> [String] -> String
on intercalate(delim, xs)
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, delim}
    set str to xs as text
    set my text item delimiters to dlm
    str
end intercalate

-- justifyRight :: Int -> Char -> String -> String
on justifyRight(n, cFiller, strText)
    if n > length of strText then
        text -n thru -1 of ((replicate(n, cFiller) as text) & strText)
    else
        strText
    end if
end justifyRight

-- length :: [a] -> Int
on |length|(xs)
    set c to class of xs
    if list is c or string is c then
        length of xs
    else
        (2 ^ 29 - 1) -- (maxInt - simple proxy for non-finite)
    end if
end |length|

-- lookupDict :: a -> Dict -> Maybe b
on lookupDict(k, dct)
    -- Just the value of k in the dictionary,
    -- or Nothing if k is not found.
    set ca to current application
    set v to (ca's NSDictionary's dictionaryWithDictionary:dct)'s objectForKey:k
    if missing value  v then
        Just(item 1 of ((ca's NSArray's arrayWithObject:v) as list))
    else
        Nothing()
    end if
end lookupDict

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    -- The list obtained by applying f
    -- to each element of xs.
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- maximum :: Ord a => [a] -> a
on maximum(xs)
    script
        on |λ|(a, b)
            if a is missing value or b > a then
                b
            else
                a
            end if
        end |λ|
    end script
    
    foldl(result, missing value, xs)
end maximum

-- maybe :: b -> (a -> b) -> Maybe a -> b
on maybe(v, f, mb)
    -- The 'maybe' function takes a default value, a function, and a 'Maybe'
    -- value.  If the 'Maybe' value is 'Nothing', the function returns the
    -- default value.  Otherwise, it applies the function to the value inside
    -- the 'Just' and returns the result.
    if Nothing of mb then
        v
    else
        tell mReturn(f) to |λ|(Just of mb)
    end if
end maybe

-- min :: Ord a => a -> a -> a
on min(x, y)
    if y < x then
        y
    else
        x
    end if
end min

-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    -- 2nd class handler function lifted into 1st class script wrapper. 
    if script is class of f then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- quoted :: Char -> String -> String
on quoted(c, s)
    -- string flanked on both sides
    -- by a specified quote character.
    c & s & c
end quoted

-- Egyptian multiplication - progressively doubling a list, appending
-- stages of doubling to an accumulator where needed for binary 
-- assembly of a target length
-- replicate :: Int -> a -> [a]
on replicate(n, a)
    set out to {}
    if 1 > n then return out
    set dbl to {a}
    
    repeat while (1 < n)
        if 0 < (n mod 2) then set out to out & dbl
        set n to (n div 2)
        set dbl to (dbl & dbl)
    end repeat
    return out & dbl
end replicate

-- take :: Int -> [a] -> [a]
-- take :: Int -> String -> String
on take(n, xs)
    set c to class of xs
    if list is c then
        if 0 < n then
            items 1 thru min(n, length of xs) of xs
        else
            {}
        end if
    else if string is c then
        if 0 < n then
            text 1 thru min(n, length of xs) of xs
        else
            ""
        end if
    else if script is c then
        set ys to {}
        repeat with i from 1 to n
            set v to |λ|() of xs
            if missing value is v then
                return ys
            else
                set end of ys to v
            end if
        end repeat
        return ys
    else
        missing value
    end if
end take

-- unlines :: [String] -> String
on unlines(xs)
    -- A single string formed by the intercalation
    -- of a list of strings with the newline character.
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, linefeed}
    set str to xs as text
    set my text item delimiters to dlm
    str
end unlines

-- zip :: [a] -> [b] -> [(a, b)]
on zip(xs, ys)
    zipWith(Tuple, xs, ys)
end zip

-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
on zipWith(f, xs, ys)
    set lng to min(|length|(xs), |length|(ys))
    if 1 > lng then return {}
    set xs_ to take(lng, xs) -- Allow for non-finite
    set ys_ to take(lng, ys) -- generators like cycle etc
    set lst to {}
    tell mReturn(f)
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs_, item i of ys_)
        end repeat
        return lst
    end tell
end zipWith
Output:
Indices (1-based) of any duplicated characters:

                                     '' (0) -> None
                                    '.' (1) -> None
                               'abcABC' (6) -> None
                              'XYZ ZYX' (7) -> 'X' at 1, 7
'1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ' (36) -> '0' at 10, 25

Arturo

strings: [
    "", ".", "abcABC", "XYZ ZYX",
    "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
    "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X",
    "hétérogénéité",
    "🎆🎃🎇🎈", "😍😀🙌💃😍🙌", "🐠🐟🐡🦈🐬🐳🐋🐡"
]

loop strings 'str [
    chars: split str
    prints ["\"" ++ str ++ "\"" ~"(size |size str|):"]
    
    if? chars = unique chars ->
        print "has no duplicates."
    else [
        seen: #[]
        done: false

        i: 0
        while [and? i<size chars
                    not? done][
            ch: chars\[i]
            if? not? key? seen ch [
                seen\[ch]: i
            ]
            else [
                print ~"has duplicate char `|ch|` on |get seen ch| and |i|"
                done: true
            ]
            i: i+1
        ]
    ]
]
Output:
"" (size 0): has no duplicates.
"." (size 1): has no duplicates.
"abcABC" (size 6): has no duplicates.
"XYZ ZYX" (size 7): has duplicate char `Z` on 2 and 4
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (size 36): has duplicate char `0` on 9 and 24
"01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X" (size 39): has duplicate char `0` on 0 and 10
"hétérogénéité" (size 13): has duplicate char `é` on 1 and 3
"🎆🎃🎇🎈" (size 4): has no duplicates.
"😍😀🙌💃😍🙌" (size 6): has duplicate char `😍` on 0 and 4
"🐠🐟🐡🦈🐬🐳🐋🐡" (size 8): has duplicate char `🐡` on 2 and 7

AutoHotkey

unique_characters(str){
	arr := [], res := ""
	for i, v in StrSplit(str)
		arr[v] := arr[v] ? arr[v] "," i : i
	for i, v in Arr
		if InStr(v, ",")
			res .= v "|" i " @ " v "`tHex = " format("{1:X}", Asc(i)) "`n"
	Sort, res, N
	res := RegExReplace(res, "`am)^[\d,]+\|")
	res := StrSplit(res, "`n").1
	return """" str """`tlength = " StrLen(str) "`n" (res ? "Duplicates Found:`n" res : "Unique Characters")
}
Examples:
test := ["",".","abcABC","XYZ ZYX","1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"]
for i, v in test
	MsgBox % unique_characters(v)
return
Outputs:
""	length = 0
Unique Characters
---------------------------
"."	length = 1
Unique Characters
---------------------------
"abcABC"	length = 6
Duplicates Found:
a @ 1,4	Hex = 61
---------------------------
"XYZ ZYX"	length = 7
Duplicates Found:
X @ 1,7	Hex = 58
---------------------------
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"	length = 36
Duplicates Found:
0 @ 10,25	Hex = 30
---------------------------


AWK

# syntax: GAWK -f DETERMINE_IF_A_STRING_HAS_ALL_UNIQUE_CHARACTERS.AWK
BEGIN {
    for (i=0; i<=255; i++) { ord_arr[sprintf("%c",i)] = i } # build array[character]=ordinal_value
    n = split(",.,abcABC,XYZ ZYX,1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",arr,",")
    for (i in arr) {
      width = max(width,length(arr[i]))
    }
    width += 2
    fmt = "| %-*s | %-6s | %-10s | %-8s | %-3s | %-9s |\n"
    head1 = head2 = sprintf(fmt,width,"string","length","all unique","1st diff","hex","positions")
    gsub(/[^|\n]/,"-",head1)
    printf(head1 head2 head1) # column headings
    for (i=1; i<=n; i++) {
      main(arr[i])
    }
    printf(head1) # column footing
    exit(0)
}
function main(str,  c,hex,i,leng,msg,position1,position2,tmp_arr) {
    msg = "yes"
    leng = length(str)
    for (i=1; i<=leng; i++) {
      c = substr(str,i,1)
      if (c in tmp_arr) {
        msg = "no"
        first_diff = "'" c "'"
        hex = sprintf("%2X",ord_arr[c])
        position1 = index(str,c)
        position2 = i
        break
      }
      tmp_arr[c] = ""
    }
    printf(fmt,width,"'" str "'",leng,msg,first_diff,hex,position1 " " position2)
}
function max(x,y) { return((x > y) ? x : y) }
Output:
|----------------------------------------|--------|------------|----------|-----|-----------|
| string                                 | length | all unique | 1st diff | hex | positions |
|----------------------------------------|--------|------------|----------|-----|-----------|
| ''                                     | 0      | yes        |          |     |           |
| '.'                                    | 1      | yes        |          |     |           |
| 'abcABC'                               | 6      | yes        |          |     |           |
| 'XYZ ZYX'                              | 7      | no         | 'Z'      | 5A  | 3 5       |
| '1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ' | 36     | no         | '0'      | 30  | 10 25     |
|----------------------------------------|--------|------------|----------|-----|-----------|

BASIC

BASIC256

Translation of: FreeBASIC
subroutine CaracteresUnicos (cad$)
	lngt = length(cad$)
	print 'Cadena = "'; cad$; '", longitud = '; lngt
	for i = 1 to lngt
		for j = i + 1 to lngt
			if mid(cad$,i,1) = mid(cad$,j,1) then
				print " Primer duplicado en las posiciones " & i & " y " & j & ", caracter = '" &  mid(cad$,i,1) & "', valor hex = " & tohex(asc(mid(cad$,i,1)))
				return
			end if
		next j
	next i
	print " Todos los caracteres son unicos." & chr(10)
end subroutine

call CaracteresUnicos("")
call CaracteresUnicos(".")
call CaracteresUnicos("abcABC")
call CaracteresUnicos("XYZ ZYX")
call CaracteresUnicos("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ")
Output:
Similar as FreeBASIC entry.

Chipmunk Basic

Works with: Chipmunk Basic version 3.6.4
Translation of: FreeBASIC
100 cls
110 sub caracteresunicos(cad$)
120  lngt = len(cad$)
130  print 'Cadena = "';cad$;'" longitud = ';lngt
140  for i = 1 to lngt
150   for j = i+1 to lngt
160    if mid$(cad$,i,1) = mid$(cad$,j,1) then
170     print " Primer duplicado en las posiciones ";i;" y ";j;", caracter = '";mid$(cad$,i,1);"', valor hex = ";hex$(asc(mid$(cad$,i,1)))
180     print
190     exit sub
200    endif
210   next j
220  next i
230  print " Todos los caracteres son unicos.";chr$(10)
240 end sub
250 caracteresunicos("")
260 caracteresunicos(".")
270 caracteresunicos("abcABC")
280 caracteresunicos("XYZ ZYX")
290 caracteresunicos("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ")
300 end
Output:
Same as FreeBASIC entry.

FreeBASIC

Sub CaracteresUnicos (cad As String)
    Dim As Integer lngt = Len(cad)
    Print "Cadena = """; cad; """, longitud = "; lngt
    For i As Integer = 1 To lngt
        For j As Integer = i + 1 To lngt
            If Mid(cad,i,1) = Mid(cad,j,1) Then
                Print " Primer duplicado en las posiciones " & i & _
                " y " & j & ", caracter = '" &  Mid(cad,i,1) & _
                "', valor hex = " & Hex(Asc(Mid(cad,i,1)))
                Print
                Exit Sub
            End If
        Next j
    Next i
    Print " Todos los caracteres son unicos." & Chr(10)
End Sub

CaracteresUnicos ("")
CaracteresUnicos (".")
CaracteresUnicos ("abcABC")
CaracteresUnicos ("XYZ ZYX")
CaracteresUnicos ("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ")
Sleep
Output:
Cadena = "", longitud =  0
 Todos los caracteres son unicos.

Cadena = ".", longitud =  1
 Todos los caracteres son unicos.

Cadena = "abcABC", longitud =  6
 Todos los caracteres son unicos.

Cadena = "XYZ ZYX", longitud =  7
 Primer duplicado en las posiciones 1 y 7, caracter = 'X', valor hex = 58

Cadena = "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ", longitud =  36
 Primer duplicado en las posiciones 10 y 25, caracter = '0', valor hex = 30

FutureBasic

void local fn StringHasUniqueCharacters( string as CFStringRef )
  long i, j, length = len( string )
  
  if length == 0 then printf @"The string \"\" is empty and thus has no characters to compare.\n" : exit fn
  
  printf @"The string: \"%@\" has %ld characters.", string, length
  
  for i = 0 to length - 1
    for j = i + 1 to length - 1
      if ( fn StringIsEqual( mid( string, i, 1 ), mid( string, j, 1 ) ) )
        CFStringRef duplicate = mid( string, i, 1 )
        printf @"The first duplicate character, \"%@\", is found at positions %ld and %ld.", duplicate, i, j
        printf @"The hex value of \"%@\" is: 0X%x\n", duplicate, fn StringCharacterAtIndex( duplicate, 0 )
        exit fn
      end if
    next
  next
  printf @"All characters in string are unique.\n"
end fn

fn StringHasUniqueCharacters( @"" )
fn StringHasUniqueCharacters( @"." )
fn StringHasUniqueCharacters( @"abcABC" )
fn StringHasUniqueCharacters( @"XYZ ZYX" )
fn StringHasUniqueCharacters( @"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" )

HandleEvents
Output:
The string "" is empty and thus has no characters to compare.

The string: "." has 1 characters.
All characters in string are unique.

The string: "abcABC" has 6 characters.
All characters in string are unique.

The string: "XYZ ZYX" has 7 characters.
The first duplicate character, "X", is found at positions 0 and 6.
The hex value of "X" is: 0X58

The string: "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" has 36 characters.
The first duplicate character, "0", is found at positions 9 and 24.
The hex value of "0" is: 0X30

PureBasic

Translation of: FreeBASIC
Procedure CaracteresUnicos(cad.s)   
  lngt.i = Len(cad) 
  PrintN("Cadena = '" + cad + "' longitud = " + Str(lngt))
  For i.i = 1 To lngt 
    For j.i = i + 1 To lngt 
      If Mid(cad, i, 1) = Mid(cad, j, 1)
        PrintN(" Primer duplicado en las posiciones " + Str(i) + " y " + Str(j) + ", caracter = '"  + Mid(cad, i, 1) + "', valor hex = "  + Hex(Asc(Mid(cad, i, 1))))
        ProcedureReturn
      EndIf 
    Next
  Next
  PrintN(" Todos los caracteres son unicos.")
EndProcedure

OpenConsole()
CaracteresUnicos("") 
CaracteresUnicos(".") 
CaracteresUnicos("abcABC") 
CaracteresUnicos("XYZ ZYX") 
CaracteresUnicos("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ")
PrintN(#CRLF$ + "--- Press ENTER to exit ---"): Input()
CloseConsole()
Output:
Similar as FreeBASIC entry.

Visual Basic .NET

Translation of: C#
Module Module1

    Sub Main()
        Dim input() = {"", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"}
        For Each s In input
            Console.WriteLine($"'{s}' (Length {s.Length}) " + String.Join(", ", s.Select(Function(c, i) (c, i)).GroupBy(Function(t) t.c).Where(Function(g) g.Count() > 1).Select(Function(g) $"'{g.Key}' (0X{AscW(g.Key):X})[{String.Join(", ", g.Select(Function(t) t.i))}]").DefaultIfEmpty("All characters are unique.")))
        Next
    End Sub

End Module
Output:
'' (Length 0) All characters are unique.
'.' (Length 1) All characters are unique.
'abcABC' (Length 6) All characters are unique.
'XYZ ZYX' (Length 7) 'X' (0X58)[0, 6], 'Y' (0X59)[1, 5], 'Z' (0X5A)[2, 4]
'1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ' (Length 36) '0' (0X30)[9, 24]

Yabasic

Translation of: FreeBASIC
sub caracteresunicos (cad$)
    local lngt, i, j

	lngt = len(cad$)
    print "cadena = \"", cad$, "\", longitud = ", lngt
    for i = 1 to lngt
        for j = i + 1 to lngt
            if mid$(cad$,i,1) = mid$(cad$,j,1) then
                print " Primer duplicado en las posiciones ", i, " y ", j, ", caracter = \'",  mid$(cad$,i,1), "\', valor hex = ", hex$(asc(mid$(cad$,i,1)))
                print
                return
            end if
        next j
    next i
    print " Todos los caracteres son unicos.\n"
end sub

caracteresunicos ("")
caracteresunicos (".")
caracteresunicos ("abcABC")
caracteresunicos ("XYZ ZYX")
caracteresunicos ("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ")
Output:
Same as FreeBASIC entry.


BQN

O(n^2) method used for finding indices.

Hex function and loop similar to Determine if a string has all the same characters

Check=⌜˜
Hex("0A"+¨1026)16{𝕗|⌊÷𝕗(1+·𝕗1⌈⊢)}
 
{
  𝕊 str:
  rCheck str
  •Out {
    ´1=+´˘r ? "All characters are unique" ;
    i/⊏(1<+´˘r)/r
    ch(i)str
    "'"ch"' (hex: "(Hex ch-@)", indices: "(•Fmt i)") duplicated in string '"str"'"
  }  
}¨
  ""
  "."
  "abcABC"
  "XYZ  ZYX"
  "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"

All characters are unique
All characters are unique
All characters are unique
'X' (hex: 58, indices: ⟨ 0 7 ⟩) duplicated in string 'XYZ  ZYX'
'0' (hex: 30, indices: ⟨ 9 24 ⟩) duplicated in string '1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ'

C

In interactive mode, strings with spaces have to be enclosed in double quotes ("")

#include<stdbool.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>

typedef struct positionList{
    int position;
    struct positionList *next;
}positionList;

typedef struct letterList{
    char letter;
    int repititions;
    positionList* positions;
    struct letterList *next;
}letterList;

letterList* letterSet;
bool duplicatesFound = false;

void checkAndUpdateLetterList(char c,int pos){
    bool letterOccurs = false;
    letterList *letterIterator,*newLetter;
    positionList *positionIterator,*newPosition;

    if(letterSet==NULL){
        letterSet = (letterList*)malloc(sizeof(letterList));
        letterSet->letter = c;
        letterSet->repititions = 0;

        letterSet->positions = (positionList*)malloc(sizeof(positionList));
        letterSet->positions->position = pos;
        letterSet->positions->next = NULL;

        letterSet->next = NULL;
    }

    else{
        letterIterator = letterSet;

        while(letterIterator!=NULL){
            if(letterIterator->letter==c){
                letterOccurs = true;
                duplicatesFound = true;

                letterIterator->repititions++;
                positionIterator = letterIterator->positions;

                while(positionIterator->next!=NULL)
                    positionIterator = positionIterator->next;
                
                newPosition = (positionList*)malloc(sizeof(positionList));
                newPosition->position = pos;
                newPosition->next = NULL;

                positionIterator->next = newPosition;
            }
            if(letterOccurs==false && letterIterator->next==NULL)
                break;
            else
                letterIterator = letterIterator->next;
        }

        if(letterOccurs==false){
            newLetter = (letterList*)malloc(sizeof(letterList));
            newLetter->letter = c;

            newLetter->repititions = 0;

            newLetter->positions = (positionList*)malloc(sizeof(positionList));
            newLetter->positions->position = pos;
            newLetter->positions->next = NULL;

            newLetter->next = NULL;

            letterIterator->next = newLetter;
        } 
    }
}

void printLetterList(){
    positionList* positionIterator;
    letterList* letterIterator = letterSet;

    while(letterIterator!=NULL){
        if(letterIterator->repititions>0){
            printf("\n'%c' (0x%x) at positions :",letterIterator->letter,letterIterator->letter);

            positionIterator = letterIterator->positions;

            while(positionIterator!=NULL){
                printf("%3d",positionIterator->position + 1);
                positionIterator = positionIterator->next;
            }
        }

        letterIterator = letterIterator->next;
    }
    printf("\n");
}

int main(int argc,char** argv)
{
    int i,len;
    
    if(argc>2){
        printf("Usage : %s <Test string>\n",argv[0]);
        return 0;
    }

    if(argc==1||strlen(argv[1])==1){
        printf("\"%s\" - Length %d - Contains only unique characters.\n",argc==1?"":argv[1],argc==1?0:1);
        return 0;
    }

    len = strlen(argv[1]);

    for(i=0;i<len;i++){
        checkAndUpdateLetterList(argv[1][i],i);
    }

    printf("\"%s\" - Length %d - %s",argv[1],len,duplicatesFound==false?"Contains only unique characters.\n":"Contains the following duplicate characters :");

    if(duplicatesFound==true)
        printLetterList();
    
    return 0;
}

Output, test strings from the task Determine_if_a_string_has_all_the_same_characters are also included :

abhishek_ghosh@Azure:~/doodles$ ./a.out
"" - Length 0 - Contains only unique characters.
abhishek_ghosh@Azure:~/doodles$ ./a.out .
"." - Length 1 - Contains only unique characters.
abhishek_ghosh@Azure:~/doodles$ ./a.out abcABC
"abcABC" - Length 6 - Contains only unique characters.
abhishek_ghosh@Azure:~/doodles$ ./a.out "XYZ YZX"
"XYZ YZX" - Length 7 - Contains the following duplicate characters :
'X' (0x58) at positions :  1  7
'Y' (0x59) at positions :  2  5
'Z' (0x5a) at positions :  3  6
abhishek_ghosh@Azure:~/doodles$ ./a.out 1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" - Length 36 - Contains the following duplicate characters :
'0' (0x30) at positions : 10 25
abhishek_ghosh@Azure:~/doodles$ ./a.out "   "
"   " - Length 3 - Contains the following duplicate characters :
' ' (0x20) at positions :  1  2  3
abhishek_ghosh@Azure:~/doodles$ ./a.out 2
"2" - Length 1 - Contains only unique characters.
abhishek_ghosh@Azure:~/doodles$ ./a.out 333
"333" - Length 3 - Contains the following duplicate characters :
'3' (0x33) at positions :  1  2  3
abhishek_ghosh@Azure:~/doodles$ ./a.out .55
".55" - Length 3 - Contains the following duplicate characters :
'5' (0x35) at positions :  2  3
abhishek_ghosh@Azure:~/doodles$ ./a.out tttTTT
"tttTTT" - Length 6 - Contains the following duplicate characters :
't' (0x74) at positions :  1  2  3
'T' (0x54) at positions :  4  5  6
abhishek_ghosh@Azure:~/doodles$ ./a.out "4444 444k"
"4444 444k" - Length 9 - Contains the following duplicate characters :
'4' (0x34) at positions :  1  2  3  4  6  7  8

C#

using System;
using System.Linq;

public class Program
{
    static void Main
    {
        string[] input = {"", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"};
        foreach (string s in input) {
            Console.WriteLine($"\"{s}\" (Length {s.Length}) " +
                string.Join(", ",
                    s.Select((c, i) => (c, i))
                    .GroupBy(t => t.c).Where(g => g.Count() > 1)
                    .Select(g => $"'{g.Key}' (0X{(int)g.Key:X})[{string.Join(", ", g.Select(t => t.i))}]")
                    .DefaultIfEmpty("All characters are unique.")
                )
            );
        }
    }
}
Output:
"" (Length 0) All characters are unique.
"." (Length 1) All characters are unique.
"abcABC" (Length 6) All characters are unique.
"XYZ ZYX" (Length 7) 'X'(0X58) [0, 6], 'Y'(0X59) [1, 5], 'Z'(0X5A) [2, 4]
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (Length 36) '0'(0X30) [9, 24]

C++

#include <iostream>
#include <string>

void string_has_repeated_character(const std::string& str) {
    size_t len = str.length();
    std::cout << "input: \"" << str << "\", length: " << len << '\n';
    for (size_t i = 0; i < len; ++i) {
        for (size_t j = i + 1; j < len; ++j) {
            if (str[i] == str[j]) {
                std::cout << "String contains a repeated character.\n";
                std::cout << "Character '" << str[i]
                    << "' (hex " << std::hex << static_cast<unsigned int>(str[i])
                    << ") occurs at positions " << std::dec << i + 1
                    << " and " << j + 1 << ".\n\n";
                return;
            }
        }
    }
    std::cout << "String contains no repeated characters.\n\n";
}

int main() {
    string_has_repeated_character("");
    string_has_repeated_character(".");
    string_has_repeated_character("abcABC");
    string_has_repeated_character("XYZ ZYX");
    string_has_repeated_character("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ");
    return 0;
}
Output:
input: "", length: 0
String contains no repeated characters.

input: ".", length: 1
String contains no repeated characters.

input: "abcABC", length: 6
String contains no repeated characters.

input: "XYZ ZYX", length: 7
String contains a repeated character.
Character 'X' (hex 58) occurs at positions 1 and 7.

input: "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ", length: 36
String contains a repeated character.
Character '0' (hex 30) occurs at positions 10 and 25.

Clojure

(defn uniq-char-string [s]
  (let [len (count s)]
    (if (= len (count (set s)))
      (println (format "All %d chars unique in: '%s'" len s))
      (loop [prev-chars #{}
             idx   0
             chars (vec s)]
        (let [c (first chars)]
          (if (contains? prev-chars c)
            (println (format "'%s' (len: %d) has '%c' duplicated at idx: %d"
                             s len c idx))
            (recur (conj prev-chars c)
                   (inc idx)
                   (rest chars))))))))
Output:
All 0 chars unique in: ''
All 1 chars unique in: '.'
All 6 chars unique in: 'abcABC'
'XYZ ZYX' (len: 7) has 'Z' duplicated at idx: 4
'1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ' (len: 36) has '0' duplicated at idx: 24
All 4 chars unique in: 'asdf'
'asdfas' (len: 6) has 'a' duplicated at idx: 4
'foofoo' (len: 6) has 'o' duplicated at idx: 2
'foOfoo' (len: 6) has 'f' duplicated at idx: 3

Common Lisp

;; * Loading the iterate library
(eval-when (:compile-toplevel :load-toplevel)
  (ql:quickload '("iterate")))

;; * The package definition
(defpackage :unique-string
  (:use :common-lisp :iterate))
(in-package :unique-string)

;; * The test strings
(defparameter test-strings
  '("" "." "abcABC" "XYZ ZYX" "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"))

;; * The function
(defun unique-string (string)
  "Returns T if STRING has all unique characters."
  (iter
    (with hash = (make-hash-table :test #'equal))
    (with len = (length string))
    (with result = T)
    (for char in-string string)
    (for pos  from 0)
    (initially (format t "String ~a of length ~D~%" string len))
    (if #1=(gethash char hash)
        ;; The character was seen before
        (progn
          (format t
                  " --> Non-unique character ~c #X~X found at position ~D,
                  before ~D ~%" char (char-code char) pos #1#)
          (setf result nil))
        ;; The character was not seen before, saving its position
        (setf #1# pos))
    (finally (when result
               (format t " --> All characters are unique~%"))
             (return result))))

(mapcar #'unique-string test-strings)
Output:
String  of length 0
 --> All characters are unique
String . of length 1
 --> All characters are unique
String abcABC of length 6
 --> All characters are unique
String XYZ ZYX of length 7
 --> Non-unique character Z #X5A found at position 4,
                  before 2 
 --> Non-unique character Y #X59 found at position 5,
                  before 1 
 --> Non-unique character X #X58 found at position 6,
                  before 0 
String 1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ of length 36
 --> Non-unique character 0 #X30 found at position 24,
                  before 9

D

Translation of: C++
import std.stdio;

void uniqueCharacters(string str) {
    writefln("input: `%s`, length: %d", str, str.length);
    foreach (i; 0 .. str.length) {
        foreach (j; i + 1 .. str.length) {
            if (str[i] == str[j]) {
                writeln("String contains a repeated character.");
                writefln("Character '%c' (hex %x) occurs at positions %d and %d.", str[i], str[i], i + 1, j + 1);
                writeln;
                return;
            }
        }
    }
    writeln("String contains no repeated characters.");
    writeln;
}

void main() {
    uniqueCharacters("");
    uniqueCharacters(".");
    uniqueCharacters("abcABC");
    uniqueCharacters("XYZ ZYX");
    uniqueCharacters("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ");
}
Output:
input: ``, length: 0
String contains no repeated characters.

input: `.`, length: 1
String contains no repeated characters.

input: `abcABC`, length: 6
String contains no repeated characters.

input: `XYZ ZYX`, length: 7
String contains a repeated character.
Character 'X' (hex 58) occurs at positions 1 and 7.

input: `1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ`, length: 36
String contains a repeated character.
Character '0' (hex 30) occurs at positions 10 and 25.

Delphi

Translation of: Cpp
program Determine_if_a_string_has_all_unique_characters;

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

procedure string_has_repeated_character(str: string);
var
  len, i, j: Integer;
begin
  len := length(str);
  Writeln('input: \', str, '\, length: ', len);
  for i := 1 to len - 1 do
  begin
    for j := i + 1 to len do
    begin
      if str[i] = str[j] then
      begin
        Writeln('String contains a repeated character.');
        Writeln('Character "', str[i], '" (hex ', ord(str[i]).ToHexString,
          ') occurs at positions ', i + 1, ' and ', j + 1, '.'#10);
        Exit;
      end;
    end;
  end;
  Writeln('String contains no repeated characters.' + sLineBreak);
end;

begin
  string_has_repeated_character('');
  string_has_repeated_character('.');
  string_has_repeated_character('abcABC');
  string_has_repeated_character('XYZ ZYX');
  string_has_repeated_character('1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ');
  readln;
end.
Output:

Delphi strings are start index in one.

input: \\, length: 0
String contains no repeated characters.

input: \.\, length: 1
String contains no repeated characters.

input: \abcABC\, length: 6
String contains no repeated characters.

input: \XYZ ZYX\, length: 7
String contains a repeated character.
Character "X" (hex 0058) occurs at positions 2 and 8.

input: \1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ\, length: 36
String contains a repeated character.
Character "0" (hex 0030) occurs at positions 11 and 26.

EasyLang

func$ hex h .
   for d in [ h div 16 h mod 16 ]
      if d > 9
         d += 7
      .
      h$ &= strchar (d + 48)
   .
   return h$
.
proc unichar s$ . .
   len d[] 65536
   s$[] = strchars s$
   for i to len s$[]
      h = strcode s$[i]
      if d[h] <> 0
         write " --> duplicates: '" & s$[i] & "' (" & hex h & "h)"
         print "'  positions: " & d[h] & ", " & i
         return
      .
      d[h] = i
   .
   print "ok"
.
repeat
   s$ = input
   until s$ = "EOF"
   print "'" & s$ & "'" & " length " & len s$
   unichar s$
   print ""
.
input_data

.
abcABC
XYZ ZYX
1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ
EOF

Erlang

-module(string_examples).
-export([all_unique/1, all_unique_examples/0]).

all_unique(String) ->
    CharPosPairs = lists:zip(String, lists:seq(1, length(String))),
    Duplicates = [{Char1, Pos1, Pos2} || {Char1, Pos1} <- CharPosPairs,
                                         {Char2, Pos2} <- CharPosPairs,
                                         Char1 =:= Char2,
                                         Pos2 > Pos1],
    case Duplicates of
        [] ->
            all_unique;
        [{Char, P1, P2}|_] ->
            {not_all_unique, Char, P1, P2}
    end.

all_unique_examples() ->
    lists:foreach(fun (Str) ->
                          io:format("String \"~ts\" (length ~p): ",
                                    [Str, length(Str)]),
                          case all_unique(Str) of
                              all_unique ->
                                  io:format("All characters unique.~n");
                              {not_all_unique, Char, P1, P2} ->
                                  io:format("First duplicate is '~tc' (0x~.16b)"
                                            " at positions ~p and ~p.~n",
                                            [Char, Char, P1, P2])
                          end
                  end,
                  ["", ".", "abcABC", "XYZ ZYX",
                   "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"]).
Output:
$ erl
Erlang/OTP 23 [erts-11.1.8] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1]

Eshell V11.1.8  (abort with ^G)
1> c(string_examples).
{ok,string_examples}
2> string_examples:all_unique_examples().
String "" (length 0): All characters unique.
String "." (length 1): All characters unique.
String "abcABC" (length 6): All characters unique.
String "XYZ ZYX" (length 7): First duplicate is 'X' (0x58) at positions 1 and 7.
String "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (length 36): First duplicate is '0' (0x30) at positions 10 and 25.
ok

F#

// Determine if a string has all unique characters. Nigel Galloway: June 9th., 2020
let fN (n:string)=n.ToCharArray()|>Array.mapi(fun n g->(n,g))|>Array.groupBy(fun (_,n)->n)|>Array.filter(fun(_,n)->n.Length>1)

let allUnique n=match fN n with
                 g when g.Length=0->printfn "All charcters in <<<%s>>> (length %d) are unique" n n.Length
                |g->Array.iter(fun(n,g)->printf "%A is repeated at positions" n; Array.iter(fun(n,_)->printf " %d" n)g;printf " ")g
                    printfn "in <<<%s>>> (length %d)" n n.Length

allUnique ""
allUnique "."
allUnique "abcABC"
allUnique "XYZ ZYX"
allUnique "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"
Output:
All charcters in <<<>>> (length 0) are unique
All charcters in <<<.>>> (length 1) are unique
All charcters in <<<abcABC>>> (length 6) are unique
'X' is repeated at positions 0 6 'Y' is repeated at positions 1 5 'Z' is repeated at positions 2 4 in <<<XYZ ZYX>>> (length 7)
'0' is repeated at positions 9 24 in <<<1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ>>> (length 36)

Factor

USING: formatting fry generalizations io kernel math.parser
sequences sets ;

: repeated ( elt seq -- )
    [ dup >hex over ] dip indices first2
    "  '%c' (0x%s) at indices %d and %d.\n" printf ;

: uniqueness-report ( str -- )
    dup dup length "%u — length %d — contains " printf
    [ duplicates ] keep over empty?
    [ 2drop "all unique characters." print ]
    [ "repeated characters:" print '[ _ repeated ] each ] if ;

""
"."
"abcABC"
"XYZ ZYX"
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"
[ uniqueness-report nl ] 5 napply
Output:
"" — length 0 — contains all unique characters.

"." — length 1 — contains all unique characters.

"abcABC" — length 6 — contains all unique characters.

"XYZ ZYX" — length 7 — contains repeated characters:
  'Z' (0x5a) at indices 2 and 4.
  'Y' (0x59) at indices 1 and 5.
  'X' (0x58) at indices 0 and 6.

"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" — length 36 — contains repeated characters:
  '0' (0x30) at indices 9 and 24.

Fortran

program demo_verify
implicit none
    call nodup('')
    call nodup('.')
    call nodup('abcABC')
    call nodup('XYZ ZYX')
    call nodup('1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ')
contains

subroutine nodup(str)
character(len=*),intent(in)  :: str
character(len=*),parameter   :: g='(*(g0))'
character(len=:),allocatable :: ch
integer                      :: where
integer                      :: i
   where=0
   ch=''

   do i=1,len(str)-1
      ch=str(i:i)
      where=index(str(i+1:),ch)
      if(where.ne.0)then
         where=where+i
         exit
      endif
   enddo

   if(where.eq.0)then
     write(*,g)'STR: "',str,'"',new_line('a'),'LEN: ',len(str),'. No duplicate characters found'
   else
     write(*,g)'STR: "',str,'"'
     write(*,'(a,a,t1,a,a)')repeat(' ',where+5),'^',repeat(' ',i+5),'^'
     write(*,g)'LEN: ',len(str), &
     & '. Duplicate chars. First duplicate at positions ',i,' and ',where, &
     & ' where a ','"'//str(where:where)//'"(hex:',hex(str(where:where)),') was found.'
   endif
   write(*,*)

end subroutine nodup

function hex(ch) result(hexstr)
character(len=1),intent(in) :: ch
character(len=:),allocatable :: hexstr
   hexstr=repeat(' ',100)
   write(hexstr,'(Z0)')ch
   hexstr=trim(hexstr)
end function hex

end program demo_verify
Output:
STR: ""
LEN: 0. No duplicate characters found

STR: "."
LEN: 1. No duplicate characters found

STR: "abcABC"
LEN: 6. No duplicate characters found

STR: "XYZ ZYX"
      ^     ^
LEN: 7. Duplicate chars. First duplicate at positions 1 and 7 where a "X"(hex:58) was found.

STR: "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"
               ^              ^
LEN: 36. Duplicate chars. First duplicate at positions 10 and 25 where a "0"(hex:30) was found.

Go

package main

import "fmt"

func analyze(s string) {
    chars := []rune(s)
    le := len(chars)
    fmt.Printf("Analyzing %q which has a length of %d:\n", s, le)
    if le > 1 {
        for i := 0; i < le-1; i++ {
            for j := i + 1; j < le; j++ {
                if chars[j] == chars[i] {
                    fmt.Println("  Not all characters in the string are unique.")
                    fmt.Printf("  %q (%#[1]x) is duplicated at positions %d and %d.\n\n", chars[i], i+1, j+1)
                    return
                }
            }
        }
    }
    fmt.Println("  All characters in the string are unique.\n")
}

func main() {
    strings := []string{
        "",
        ".",
        "abcABC",
        "XYZ ZYX",
        "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
        "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X",
        "hétérogénéité",
        "🎆🎃🎇🎈",
        "😍😀🙌💃😍🙌",
        "🐠🐟🐡🦈🐬🐳🐋🐡",
    }
    for _, s := range strings {
        analyze(s)
    }
}
Output:
Analyzing "" which has a length of 0:
  All characters in the string are unique.

Analyzing "." which has a length of 1:
  All characters in the string are unique.

Analyzing "abcABC" which has a length of 6:
  All characters in the string are unique.

Analyzing "XYZ ZYX" which has a length of 7:
  Not all characters in the string are unique.
  'X' (0x58) is duplicated at positions 1 and 7.

Analyzing "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" which has a length of 36:
  Not all characters in the string are unique.
  '0' (0x30) is duplicated at positions 10 and 25.

Analyzing "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X" which has a length of 39:
  Not all characters in the string are unique.
  '0' (0x30) is duplicated at positions 1 and 11.

Analyzing "hétérogénéité" which has a length of 13:
  Not all characters in the string are unique.
  'é' (0xe9) is duplicated at positions 2 and 4.

Analyzing "🎆🎃🎇🎈" which has a length of 4:
  All characters in the string are unique.

Analyzing "😍😀🙌💃😍🙌" which has a length of 6:
  Not all characters in the string are unique.
  '😍' (0x1f60d) is duplicated at positions 1 and 5.

Analyzing "🐠🐟🐡🦈🐬🐳🐋🐡" which has a length of 8:
  Not all characters in the string are unique.
  '🐡' (0x1f421) is duplicated at positions 3 and 8.

Groovy

Translation of: Java
class StringUniqueCharacters {
    static void main(String[] args) {
        printf("%-40s  %2s  %10s  %8s  %s  %s%n", "String", "Length", "All Unique", "1st Diff", "Hex", "Positions")
        printf("%-40s  %2s  %10s  %8s  %s  %s%n", "------------------------", "------", "----------", "--------", "---", "---------")
        for (String s : ["", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"]) {
            processString(s)
        }
    }

    private static void processString(String input) {
        Map<Character, Integer> charMap = new HashMap<>()
        char dup = 0
        int index = 0
        int pos1 = -1
        int pos2 = -1
        for (char key : input.toCharArray()) {
            index++
            if (charMap.containsKey(key)) {
                dup = key
                pos1 = charMap.get(key)
                pos2 = index
                break
            }
            charMap.put(key, index)
        }
        String unique = (int) dup == 0 ? "yes" : "no"
        String diff = (int) dup == 0 ? "" : "'" + dup + "'"
        String hex = (int) dup == 0 ? "" : Integer.toHexString((int) dup).toUpperCase()
        String position = (int) dup == 0 ? "" : pos1 + " " + pos2
        printf("%-40s  %-6d  %-10s  %-8s  %-3s  %-5s%n", input, input.length(), unique, diff, hex, position)
    }
}
Output:
String                                    Length  All Unique  1st Diff  Hex  Positions
------------------------                  ------  ----------  --------  ---  ---------
                                          0       yes                             
.                                         1       yes                             
abcABC                                    6       yes                             
XYZ ZYX                                   7       no          'Z'       5A   3 5  
1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ      36      no          '0'       30   10 25

Haskell

import Data.List (groupBy, intersperse, sort, transpose)
import Data.Char (ord, toUpper)
import Data.Function(on) 
import Numeric (showHex)


hexFromChar :: Char -> String
hexFromChar c = map toUpper $ showHex (ord c) ""
 
string :: String -> String
string xs = ('\"' : xs) <> "\""
 
char :: Char -> String
char c = ['\'', c, '\'']
 
size :: String -> String
size = show . length
 
positions :: (Int, Int) -> String
positions (a, b) = show a <> " " <> show b
 
forTable :: String -> [String]
forTable xs = string xs : go (allUnique xs)
  where
    go Nothing = [size xs, "yes", "", "", ""]
    go (Just (u, ij)) = [size xs, "no", char u, hexFromChar u, positions ij]
 
showTable :: Bool -> Char -> Char -> Char -> [[String]] -> String
showTable _ _ _ _ [] = []
showTable header ver hor sep contents =
  unlines $
  hr :
  (if header
     then z : hr : zs
     else intersperse hr zss) <>
  [hr]
  where
    vss = map (map length) contents
    ms = map maximum (transpose vss) :: [Int]
    hr = concatMap (\n -> sep : replicate n hor) ms <> [sep]
    top = replicate (length hr) hor
    bss = map (map (`replicate` ' ') . zipWith (-) ms) vss
    zss@(z:zs) =
      zipWith
        (\us bs -> concat (zipWith (\x y -> (ver : x) <> y) us bs) <> [ver])
        contents
        bss
 
table xs =
  showTable
    True
    '|'
    '-'
    '+'
    (["string", "length", "all unique", "1st diff", "hex", "positions"] :
     map forTable xs)
 
allUnique
  :: (Ord b, Ord a, Num b, Enum b)
  => [a] -> Maybe (a, (b, b))
allUnique xs = go . groupBy (on (==) fst) . sort . zip xs $ [0 ..]
  where
    go [] = Nothing
    go ([_]:us) = go us
    go (((u, i):(_, j):_):_) = Just (u, (i, j))
 
main :: IO ()
main =
  putStrLn $
  table ["", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"]
Output:
+--------------------------------------+------+----------+--------+---+---------+
|string                                |length|all unique|1st diff|hex|positions|
+--------------------------------------+------+----------+--------+---+---------+
|""                                    |0     |yes       |        |   |         |
|"."                                   |1     |yes       |        |   |         |
|"abcABC"                              |6     |yes       |        |   |         |
|"XYZ ZYX"                             |7     |no        |'X'     |58 |0 6      |
|"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"|36    |no        |'0'     |30 |9 24     |
+--------------------------------------+------+----------+--------+---+---------+

Alternatively, defining a duplicatedCharIndices function in terms of sortOn, groupBy, and filter:

import Data.List (groupBy, intercalate, sortOn)
import Data.Function (on)
import Numeric (showHex)
import Data.Char (ord)


------------- INDICES OF DUPLICATED CHARACTERS -----------

duplicatedCharIndices :: String -> Maybe (Char, [Int])
duplicatedCharIndices s
  | null duplicates = Nothing
  | otherwise =
    Just $
    ((,) . (snd . head) <*> fmap fst) (head (sortOn (fst . head) duplicates))
  where
    duplicates =
      filter ((1 <) . length) $
      groupBy (on (==) snd) $ sortOn snd $ zip [0 ..] s


--------------------------- TEST -------------------------
main :: IO ()
main =
  putStrLn $
  fTable
    "First duplicated character, if any:"
    (fmap (<>) show <*> ((" (" <>) . (<> ")") . show . length))
    (maybe
       "None"
       (\(c, ixs) ->
           unwords
             [ show c
             , "(0x" <> showHex (ord c) ") at"
             , intercalate ", " (show <$> ixs)
             ]))
    duplicatedCharIndices
    ["", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"]


------------------------- DISPLAY ------------------------

fTable :: String -> (a -> String) -> (b -> String) -> (a -> b) -> [a] -> String
fTable s xShow fxShow f xs =
  unlines $
  s : fmap (((<>) . rjust w ' ' . xShow) <*> ((" -> " <>) . fxShow . f)) xs
  where
    rjust n c = drop . length <*> (replicate n c <>)
    w = maximum (length . xShow <$> xs)
Output:
First duplicated character, if any:
                                     "" (0) -> None
                                    "." (1) -> None
                               "abcABC" (6) -> None
                              "XYZ ZYX" (7) -> 'X' (0x58) at 0, 6
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (36) -> '0' (0x30) at 9, 24


Or, as an alternative to grouping and sorting – folding a string down to a Map of indices:

import qualified Safe as S
import qualified Data.Map.Strict as M
import Data.List (intercalate, foldl') --'
import Data.Ord (comparing)
import Numeric (showHex)
import Data.Char (ord)


----------- INDICES OF ANY DUPLICATED CHARACTERS ---------

duplicatedCharIndices :: String -> Maybe (Char, [Int])
duplicatedCharIndices xs =
  S.minimumByMay
    (comparing (head . snd))
    (M.toList
       (M.filter
          ((1 <) . length)
          (foldl' --'
             (\a (i, c) -> M.insert c (maybe [i] (<> [i]) (M.lookup c a)) a)
             M.empty
             (zip [0 ..] xs))))

-- OR, fusing filter, toList, and minimumByMay down to a single fold:
duplicatedCharIndices_ :: String -> Maybe (Char, [Int])
duplicatedCharIndices_ xs =
  M.foldrWithKey
    go
    Nothing
    (foldl' --'
       (\a (i, c) -> M.insert c (maybe [i] (<> [i]) (M.lookup c a)) a)
       M.empty
       (zip [0 ..] xs))
  where
    go k [_] mb = mb -- Unique
    go k xs Nothing = Just (k, xs) -- Duplicated
    go k xs@(x:_) (Just (c, ys@(y:_)))
      | x < y = Just (k, xs) -- Earlier duplication
      | otherwise = Just (c, ys)

--------------------------- TEST -------------------------
main :: IO ()
main =
  putStrLn $
  fTable
    "First duplicated character, if any:"
    ((<>) <$> show <*> ((" (" <>) . (<> ")") . show . length))
    (maybe
       "None"
       (\(c, ixs) ->
           unwords
             [ show c
             , "(0x" <> showHex (ord c) ") at"
             , intercalate ", " (show <$> ixs)
             ]))
    duplicatedCharIndices_
    ["", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"]

------------------------- DISPLAY ------------------------
fTable :: String -> (a -> String) -> (b -> String) -> (a -> b) -> [a] -> String
fTable s xShow fxShow f xs =
  unlines $
  s : fmap (((<>) . rjust w ' ' . xShow) <*> ((" -> " <>) . fxShow . f)) xs
  where
    rjust n c = drop . length <*> (replicate n c <>)
    w = maximum (length . xShow <$> xs)
Output:
First duplicated character, if any:
                                     "" (0) -> None
                                    "." (1) -> None
                               "abcABC" (6) -> None
                              "XYZ ZYX" (7) -> 'X' (0x58) at 0, 6
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (36) -> '0' (0x30) at 9, 24

J

Quotes surround the literals to make the computed one-at-a-time results present well in the combined table.

rc_unique=: monad define
 string=. '"' , y , '"'
 self_classification=. = y  NB. deprecated- consumes space proportional to the squared tally of y  (*: # y)
 is_unique=. self_classification =&# y
 if. is_unique do.
  (# y) ; string ; 'unique'
 else.
  duplicate_masks=. (#~ (1 < +/"1)) self_classification
  duplicate_characters=. ~. y #~ +./ duplicate_masks
  ASCII_values_of_duplicates=. a. i. duplicate_characters
  markers=. duplicate_masks { ' ^'
  A=. (# y) ; string , ' ' ,. markers
  B=. 'duplicate' , ASCII_values_of_duplicates ('<' , (#~ 31&<)~ , '> ASCII ' , ":@:[)"0 duplicate_characters
  A , < B
 end.
)

Tests include those of the C example and a pair of MS-DOS line terminations.

   (;:'length string analysis') , rc_unique;._2';.;abcABC;XYZ YZX;1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ;   ;2;333;.55;tttTTT;4444 444k;',(4$CRLF),';'
┌──────┬──────────────────────────────────────┬─────────────┐
│length│string                                │analysis     │
├──────┼──────────────────────────────────────┼─────────────┤
│0     │""                                    │unique       │
├──────┼──────────────────────────────────────┼─────────────┤
│1     │"."                                   │unique       │
├──────┼──────────────────────────────────────┼─────────────┤
│6     │"abcABC"                              │unique       │
├──────┼──────────────────────────────────────┼─────────────┤
│7     │"XYZ YZX"                             │duplicate    │
│      │ ^     ^                              │<X> ASCII 88 │
│      │  ^  ^                                │<Y> ASCII 89 │
│      │   ^  ^                               │<Z> ASCII 90 │
├──────┼──────────────────────────────────────┼─────────────┤
│36    │"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"│duplicate    │
│      │          ^              ^            │<0> ASCII 48 │
├──────┼──────────────────────────────────────┼─────────────┤
│3     │"   "                                 │duplicate    │
│      │ ^^^                                  │< > ASCII 32 │
├──────┼──────────────────────────────────────┼─────────────┤
│1     │"2"                                   │unique       │
├──────┼──────────────────────────────────────┼─────────────┤
│3     │"333"                                 │duplicate    │
│      │ ^^^                                  │<3> ASCII 51 │
├──────┼──────────────────────────────────────┼─────────────┤
│3     │".55"                                 │duplicate    │
│      │  ^^                                  │<5> ASCII 53 │
├──────┼──────────────────────────────────────┼─────────────┤
│6     │"tttTTT"                              │duplicate    │
│      │ ^^^                                  │<t> ASCII 116│
│      │    ^^^                               │<T> ASCII 84 │
├──────┼──────────────────────────────────────┼─────────────┤
│9     │"4444 444k"                           │duplicate    │
│      │ ^^^^ ^^^                             │<4> ASCII 52 │
├──────┼──────────────────────────────────────┼─────────────┤
│4     │"    "                                │duplicate    │
│      │ ^ ^                                  │<> ASCII 13  │
│      │  ^ ^                                 │<> ASCII 10  │
└──────┴──────────────────────────────────────┴─────────────┘

More uniqueness tests with performance comparison

NB. unique_index answers "Do the left and right indexes match?"
unique_index=: (i. -: i:)~
assert 0 1 -: 2 unique_index\0 0 1

NB. unique_set answers "Are lengths of the nub and original equal?"
unique_set=: -:&# ~.
assert 0 1 -: _2 unique_set\'aab'

NB. unique_nubsieve answers "Are the items unique?"
unique_nubsieve=: 0 -.@:e. ~:
assert 0 1 -: _2 unique_nubsieve\'aab'

Note'compared to nubsieve'
  the index method takes 131% longer and 15 times additional memory
  the set formation method 15% longer and uses 7 times additional memory.
)

Java

import java.util.HashMap;
import java.util.Map;

//  Title:  Determine if a string has all unique characters

public class StringUniqueCharacters {

    public static void main(String[] args) {
        System.out.printf("%-40s  %2s  %10s  %8s  %s  %s%n", "String", "Length", "All Unique", "1st Diff", "Hex", "Positions");
        System.out.printf("%-40s  %2s  %10s  %8s  %s  %s%n", "------------------------", "------", "----------", "--------", "---", "---------");
        for ( String s : new String[] {"", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"} ) {
            processString(s);
        }
    }
    
    
    
    private static void processString(String input) {
        Map<Character,Integer> charMap = new HashMap<>(); 
        char dup = 0;
        int index = 0;
        int pos1 = -1;
        int pos2 = -1;
        for ( char key : input.toCharArray() ) {
            index++;
            if ( charMap.containsKey(key) ) {
                dup = key;
                pos1 = charMap.get(key);
                pos2 = index;
                break;
            }
            charMap.put(key, index);
        }
        String unique = dup == 0 ? "yes" : "no";
        String diff = dup == 0 ? "" : "'" + dup + "'";
        String hex = dup == 0 ? "" : Integer.toHexString(dup).toUpperCase();
        String position = dup == 0 ? "" : pos1 + " " + pos2;
        System.out.printf("%-40s  %-6d  %-10s  %-8s  %-3s  %-5s%n", input, input.length(), unique, diff, hex, position);
    }

}
Output:
String                                    Length  All Unique  1st Diff  Hex  Positions
------------------------                  ------  ----------  --------  ---  ---------
                                          0       yes                             
.                                         1       yes                             
abcABC                                    6       yes                             
XYZ ZYX                                   7       no          'Z'       5A   3 5  
1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ      36      no          '0'       30   10 25

Using Java 11

import java.util.HashSet;
import java.util.List;
import java.util.OptionalInt;
import java.util.Set;

public final class DetermineUniqueCharacters {

	public static void main(String[] aArgs) {
		List<String> words = List.of( "", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" );
		
		for ( String word : words ) {		
			Set<Integer> seen = new HashSet<Integer>();
	        OptionalInt first = word.chars().filter( ch -> ! seen.add(ch) ).findFirst();
	        if ( first.isPresent() ) {	            
	            final char ch = (char) first.getAsInt();
	            final String hex = Integer.toHexString(ch).toUpperCase();
	            System.out.println("Word: \"" + word + "\" contains a repeated character.");
	            System.out.println("Character '" + ch + "' (hex " + hex + ") occurs at positions "
	            	+ word.indexOf(ch) + " and " + word.indexOf(ch, word.indexOf(ch) + 1));
	        } else {
	        	System.out.println("Word: \"" + word + "\" has all unique characters.");
	        }
	        System.out.println();			
		}
	}

}
Output:
Word: "" has all unique characters.

Word: "." has all unique characters.

Word: "abcABC" has all unique characters.

Word: "XYZ ZYX" contains a repeated character.
Character 'Z' (hex 5A) occurs at positions 2 and 4

Word: "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" contains a repeated character.
Character '0' (hex 30) occurs at positions 9 and 24

JavaScript

(() => {
    'use strict';

    // duplicatedCharIndices :: String -> Maybe (Char, [Int])
    const duplicatedCharIndices = s => {
        const
            duplicates = filter(g => 1 < g.length)(
                groupBy(on(eq)(snd))(
                    sortOn(snd)(
                        zip(enumFrom(0))(chars(s))
                    )
                )
            );
        return 0 < duplicates.length ? Just(
            fanArrow(compose(snd, fst))(map(fst))(
                sortOn(compose(fst, fst))(
                    duplicates
                )[0]
            )
        ) : Nothing();
    };

    // ------------------------TEST------------------------
    const main = () =>
        console.log(
            fTable('First duplicated character, if any:')(
                s => `'${s}' (${s.length})`
            )(maybe('None')(tpl => {
                const [c, ixs] = Array.from(tpl);
                return `'${c}' (0x${showHex(ord(c))}) at ${ixs.join(', ')}`
            }))(duplicatedCharIndices)([
                "", ".", "abcABC", "XYZ ZYX",
                "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"
            ])
        );


    // -----------------GENERIC FUNCTIONS------------------

    // Just :: a -> Maybe a
    const Just = x => ({
        type: 'Maybe',
        Nothing: false,
        Just: x
    });

    // Nothing :: Maybe a
    const Nothing = () => ({
        type: 'Maybe',
        Nothing: true,
    });

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = a => b => ({
        type: 'Tuple',
        '0': a,
        '1': b,
        length: 2
    });

    // chars :: String -> [Char]
    const chars = s => s.split('');

    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (...fs) =>
        x => fs.reduceRight((a, f) => f(a), x);

    // enumFrom :: Enum a => a -> [a]
    function* enumFrom(x) {
        let v = x;
        while (true) {
            yield v;
            v = 1 + v;
        }
    }

    // eq (==) :: Eq a => a -> a -> Bool
    const eq = a => b => a === b;

    // fanArrow (&&&) :: (a -> b) -> (a -> c) -> (a -> (b, c))
    const fanArrow = f =>
        // Compose a function from a simple value to a tuple of
        // the separate outputs of two different functions.
        g => x => Tuple(f(x))(g(x));

    // filter :: (a -> Bool) -> [a] -> [a]
    const filter = f => xs => xs.filter(f);

    // fst :: (a, b) -> a
    const fst = tpl => tpl[0];

    // fTable :: String -> (a -> String) -> (b -> String)
    //                      -> (a -> b) -> [a] -> String
    const fTable = s => xShow => fxShow => f => xs => {
        // Heading -> x display function ->
        //           fx display function ->
        //    f -> values -> tabular string
        const
            ys = xs.map(xShow),
            w = Math.max(...ys.map(length));
        return s + '\n' + zipWith(
            a => b => a.padStart(w, ' ') + ' -> ' + b
        )(ys)(
            xs.map(x => fxShow(f(x)))
        ).join('\n');
    };

    // groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
    const groupBy = fEq =>
        // Typical usage: groupBy(on(eq)(f), xs)
        xs => 0 < xs.length ? (() => {
            const
                tpl = xs.slice(1).reduce(
                    (gw, x) => {
                        const
                            gps = gw[0],
                            wkg = gw[1];
                        return fEq(wkg[0])(x) ? (
                            Tuple(gps)(wkg.concat([x]))
                        ) : Tuple(gps.concat([wkg]))([x]);
                    },
                    Tuple([])([xs[0]])
                );
            return tpl[0].concat([tpl[1]])
        })() : [];

    // length :: [a] -> Int
    const length = xs =>
        // Returns Infinity over objects without finite length.
        // This enables zip and zipWith to choose the shorter
        // argument when one is non-finite, like cycle, repeat etc
        (Array.isArray(xs) || 'string' === typeof xs) ? (
            xs.length
        ) : Infinity;

    // map :: (a -> b) -> [a] -> [b]
    const map = f => xs =>
        (Array.isArray(xs) ? (
            xs
        ) : xs.split('')).map(f);

    // maybe :: b -> (a -> b) -> Maybe a -> b
    const maybe = v =>
        // Default value (v) if m is Nothing, or f(m.Just)
        f => m => m.Nothing ? v : f(m.Just);

    // on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
    const on = f =>
        g => a => b => f(g(a))(g(b));

    // ord :: Char -> Int
    const ord = c => c.codePointAt(0);

    // showHex :: Int -> String
    const showHex = n =>
        n.toString(16);

    // snd :: (a, b) -> b
    const snd = tpl => tpl[1];

    // sortOn :: Ord b => (a -> b) -> [a] -> [a]
    const sortOn = f =>
        // Equivalent to sortBy(comparing(f)), but with f(x)
        // evaluated only once for each x in xs.
        // ('Schwartzian' decorate-sort-undecorate).
        xs => xs.map(
            x => [f(x), x]
        ).sort(
            (a, b) => a[0] < b[0] ? -1 : (a[0] > b[0] ? 1 : 0)
        ).map(x => x[1]);

    // take :: Int -> [a] -> [a]
    // take :: Int -> String -> String
    const take = n => xs =>
        'GeneratorFunction' !== xs.constructor.constructor.name ? (
            xs.slice(0, n)
        ) : [].concat.apply([], Array.from({
            length: n
        }, () => {
            const x = xs.next();
            return x.done ? [] : [x.value];
        }));

    // uncurry :: (a -> b -> c) -> ((a, b) -> c)
    const uncurry = f =>
        (x, y) => f(x)(y)

    // zip :: [a] -> [b] -> [(a, b)]
    const zip = xs => ys => {
        const
            lng = Math.min(length(xs), length(ys)),
            vs = take(lng)(ys);
        return take(lng)(xs)
            .map((x, i) => Tuple(x)(vs[i]));
    };

    // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    const zipWith = f =>
        xs => ys => {
            const
                lng = Math.min(length(xs), length(ys)),
                vs = take(lng)(ys);
            return take(lng)(xs)
                .map((x, i) => f(x)(vs[i]));
        };

    // MAIN ---
    return main();
})();
Output:
First duplicated character, if any:
                                     '' (0) -> None
                                    '.' (1) -> None
                               'abcABC' (6) -> None
                              'XYZ ZYX' (7) -> 'X' (0x58) at 0, 6
'1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ' (36) -> '0' (0x30) at 9, 24


Or, as an alternative to sorting and grouping – folding a string down to a dictionary of indices:

(() => {
    'use strict';

    // duplicatedCharIndices :: String -> Maybe (Char, [Int])
    const duplicatedCharIndices = s =>
        minimumByMay(
            comparing(compose(fst, snd))
        )(filter(x => 1 < x[1].length)(
            Object.entries(
                s.split('').reduce(
                    (a, c, i) => Object.assign(a, {
                        [c]: (a[c] || []).concat(i)
                    }), {}
                )
            )
        ));

    // ------------------------TEST------------------------
    const main = () =>
        console.log(
            fTable('First duplicated character, if any:')(
                s => `'${s}' (${s.length    })`
            )(maybe('None')(tpl => {
                const [c, ixs] = Array.from(tpl);
                return `'${c}' (0x${showHex(ord(c))}) at ${ixs.join(', ')}`
            }))(duplicatedCharIndices)([
                "", ".", "abcABC", "XYZ ZYX",
                "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"
            ])
        );


    // -----------------GENERIC FUNCTIONS------------------

    // Just :: a -> Maybe a
    const Just = x => ({
        type: 'Maybe',
        Nothing: false,
        Just: x
    });

    // Nothing :: Maybe a
    const Nothing = () => ({
        type: 'Maybe',
        Nothing: true,
    });

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = a => b => ({
        type: 'Tuple',
        '0': a,
        '1': b,
        length: 2
    });

    // chars :: String -> [Char]
    const chars = s => s.split('');

    // comparing :: (a -> b) -> (a -> a -> Ordering)
    const comparing = f =>
        x => y => {
            const
                a = f(x),
                b = f(y);
            return a < b ? -1 : (a > b ? 1 : 0);
        };

    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (...fs) =>
        x => fs.reduceRight((a, f) => f(a), x);

    // enumFrom :: Enum a => a -> [a]
    function* enumFrom(x) {
        let v = x;
        while (true) {
            yield v;
            v = 1 + v;
        }
    }

    // filter :: (a -> Bool) -> [a] -> [a]
    const filter = f => xs => xs.filter(f);

    // fst :: (a, b) -> a
    const fst = tpl => tpl[0];

    // fTable :: String -> (a -> String) -> (b -> String)
    //                      -> (a -> b) -> [a] -> String
    const fTable = s => xShow => fxShow => f => xs => {
        // Heading -> x display function ->
        //           fx display function ->
        //    f -> values -> tabular string
        const
            ys = xs.map(xShow),
            w = Math.max(...ys.map(length));
        return s + '\n' + zipWith(
            a => b => a.padStart(w, ' ') + ' -> ' + b
        )(ys)(
            xs.map(x => fxShow(f(x)))
        ).join('\n');
    };

    // length :: [a] -> Int
    const length = xs =>
        // Returns Infinity over objects without finite length.
        // This enables zip and zipWith to choose the shorter
        // argument when one is non-finite, like cycle, repeat etc
        (Array.isArray(xs) || 'string' === typeof xs) ? (
            xs.length
        ) : Infinity;

    // maybe :: b -> (a -> b) -> Maybe a -> b
    const maybe = v =>
        // Default value (v) if m is Nothing, or f(m.Just)
        f => m => m.Nothing ? v : f(m.Just);

    // minimumByMay :: (a -> a -> Ordering) -> [a] -> Maybe a
    const minimumByMay = f =>
        xs => xs.reduce((a, x) =>
            a.Nothing ? Just(x) : (
                f(x)(a.Just) < 0 ? Just(x) : a
            ), Nothing());

    // ord :: Char -> Int
    const ord = c => c.codePointAt(0);

    // showHex :: Int -> String
    const showHex = n =>
        n.toString(16);

    // snd :: (a, b) -> b
    const snd = tpl =>
        tpl[1];

    // take :: Int -> [a] -> [a]
    // take :: Int -> String -> String
    const take = n =>
        xs => 'GeneratorFunction' !== xs.constructor.constructor.name ? (
            xs.slice(0, n)
        ) : [].concat.apply([], Array.from({
            length: n
        }, () => {
            const x = xs.next();
            return x.done ? [] : [x.value];
        }));

    // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    const zipWith = f =>
        xs => ys => {
            const
                lng = Math.min(length(xs), length(ys)),
                vs = take(lng)(ys);
            return take(lng)(xs)
                .map((x, i) => f(x)(vs[i]));
        };

    // MAIN ---
    return main();
})();
Output:
First duplicated character, if any:
                                     '' (0) -> None
                                    '.' (1) -> None
                               'abcABC' (6) -> None
                              'XYZ ZYX' (7) -> 'X' (0x58) at 0, 6
'1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ' (36) -> '0' (0x30) at 9, 24

jq

"First Duplicate" is here understood to be the first character found to be a duplicate when scanning from left to right, so the First Duplicate in XYYX is Y. It would require only a trivial modification of `firstDuplicate` as defined here to implement the alternative interpretation as the first character to be duplicated.

# Emit null if there is no duplicate, else [c, [ix1, ix2]]
def firstDuplicate:
  label $out 
  | foreach explode[] as $i ({ix: -1};
    .ix += 1
    | .ix as $ix
    | .iu = ([$i] | implode)
    | .[.iu] += [ $ix] ;
    if .[.iu]|length == 2 then [.iu, .[.iu]], break $out else empty end )
    // null ;

Some helper functions for accomplishing other aspects of the task:

# hex of a number or a single (unicode) character
def hex:
  def stream:
    recurse(if . >= 16 then ./16|floor else empty end) | . % 16 ;
  if type=="string" then explode[0] else . end
  | [stream] | reverse
  |  map(if . < 10 then 48 + . else . + 87 end) | implode ;

def lpad($len): tostring | " " * ($len - width) + .;

def q: "«\(.)»";

def header:
  "\("string"|q|lpad(38)) :  |s| : C : hex  IO=0";

def data:
 "",
 ".",
 "abcABC",
 "XYZ ZYX",
 "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
 "😍😀🙌💃😍🙌" ;
The main program:
header,
  (data
   | firstDuplicate as [$k, $v]
   | "\(q|lpad(38)) : \(length|lpad(4)) : \($k // " ") : \($k |if . then hex else "  " end)   \($v // [])" )
Output:
                              «string» :  |s| : C : hex  IO=0
                                    «» :    0 :   :      []
                                   «.» :    1 :   :      []
                              «abcABC» :    6 :   :      []
                             «XYZ ZYX» :    7 : Z : 5A   [2,4]
«1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ» :   36 : 0 : 30   [9,24]
                       «😍😀🙌💃😍🙌» :    6 : 😍:1f60d [0,4]

The last line above was adjusted manually as jq has no built-in function for computing the horizontal "printing" width of unicode strings in general.

Julia

arr(s) = [c for c in s]
alldup(a) = filter(x -> length(x) > 1, [findall(x -> x == a[i], a) for i in 1:length(a)])
firstduplicate(s) = (a = arr(s); d = alldup(a); isempty(d) ? nothing : first(d))

function testfunction(strings)
    println("String                            | Length | All Unique | First Duplicate | Positions\n" *
            "-------------------------------------------------------------------------------------")
    for s in strings
        n = firstduplicate(s)
        a = arr(s)
        println(rpad(s, 38), rpad(length(s), 11), n == nothing ? "yes" :
                rpad("no               $(a[n[1]])", 26) * rpad(n[1], 4) * "$(n[2])")
    end
end

testfunction([
"",
".",
"abcABC",
"XYZ ZYX",
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
 "hétérogénéité",
"🎆🎃🎇🎈",
"😍😀🙌💃😍🙌",
"🐠🐟🐡🦈🐬🐳🐋🐡",
])
Output:
String                            | Length | All Unique | First Duplicate (Hex) | Positions
-------------------------------------------------------------------------------------------
                                      0          yes
.                                     1          yes
abcABC                                6          yes
XYZ ZYX                               7          no             X  (58)            1   7
1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ  36         no             0  (30)            10  25
hétérogénéité                         13         no             é  (e9)            2   4
🎆🎃🎇🎈                             4          yes
😍😀🙌💃😍🙌                        6          no           😍  (1f60d)         1   5
🐠🐟🐡🦈🐬🐳🐋🐡                   8          no           🐡  (1f421)         3   8

Kotlin

Translation of: Java
import java.util.HashMap

fun main() {
    System.out.printf("%-40s  %2s  %10s  %8s  %s  %s%n", "String", "Length", "All Unique", "1st Diff", "Hex", "Positions")
    System.out.printf("%-40s  %2s  %10s  %8s  %s  %s%n", "------------------------", "------", "----------", "--------", "---", "---------")
    for (s in arrayOf("", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ")) {
        processString(s)
    }
}

private fun processString(input: String) {
    val charMap: MutableMap<Char, Int?> = HashMap()
    var dup = 0.toChar()
    var index = 0
    var pos1 = -1
    var pos2 = -1
    for (key in input.toCharArray()) {
        index++
        if (charMap.containsKey(key)) {
            dup = key
            pos1 = charMap[key]!!
            pos2 = index
            break
        }
        charMap[key] = index
    }
    val unique = if (dup.toInt() == 0) "yes" else "no"
    val diff = if (dup.toInt() == 0) "" else "'$dup'"
    val hex = if (dup.toInt() == 0) "" else Integer.toHexString(dup.toInt()).toUpperCase()
    val position = if (dup.toInt() == 0) "" else "$pos1 $pos2"
    System.out.printf("%-40s  %-6d  %-10s  %-8s  %-3s  %-5s%n", input, input.length, unique, diff, hex, position)
}
Output:
String                                    Length  All Unique  1st Diff  Hex  Positions
------------------------                  ------  ----------  --------  ---  ---------
                                          0       yes                             
.                                         1       yes                             
abcABC                                    6       yes                             
XYZ ZYX                                   7       no          'Z'       5A   3 5  
1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ      36      no          '0'       30   10 25

Lua

Using regular expressions. The '-' in the pattern's '.-' is the "lazy" or "reluctant" repetition qualifier; the usual '.*' would caused pattern to match, in the first example below, the substring "cocc" instead of "coc".

local find, format = string.find, string.format
local function printf(fmt, ...) print(format(fmt,...)) end

local pattern = '(.).-%1' -- '(.)' .. '.-' .. '%1'

function report_dup_char(subject)
    local pos1, pos2, char = find(subject, pattern)

    local prefix = format('"%s" (%d)', subject, #subject)
    if pos1 then
        local byte = char:byte()
        printf("%s: '%s' (0x%02x) duplicates at %d, %d", prefix, char, byte, pos1, pos2)
    else
        printf("%s: no duplicates", prefix)
    end
end

local show = report_dup_char
show('coccyx')
show('')
show('.')
show('abcABC')
show('XYZ ZYX')
show('1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ')
Output:
"coccyx" (6): 'c' (0x63) duplicates at 1, 3
"" (0): no duplicates
"." (1): no duplicates
"abcABC" (6): no duplicates
"XYZ ZYX" (7): 'X' (0x58) duplicates at 1, 7
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (36): '0' (0x30) duplicates at 10, 25

Maple

CheckUnique:=proc(s)
	local i, index;
	printf("input: \"%s\", length: %a\n", s, StringTools:-Length(s));
	for i from 1 to StringTools:-Length(s) do
		index := StringTools:-SearchAll(s[i], s);	
		if (numelems([index]) > 1) then
			printf("The given string has duplicated characters.\n");
			printf("The first duplicated character is %a (0x%x) which appears at index %a.\n\n",
				  s[i], convert(s[i], 'bytes')[1], {index});
			return;
		end if;
	end do;
	# if no repeated found
	printf("The given string has all unique characters.\n\n");
end proc:

# Test
CheckUnique("");
CheckUnique(".");
CheckUnique("abcABC");
CheckUnique("XYZ ZYX");
CheckUnique("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ");
Output:
input: "", length: 0
The given string has all unique characters.

input: ".", length: 1
The given string has all unique characters.

input: "abcABC", length: 6
The given string has all unique characters.

input: "XYZ ZYX", length: 7
The given string has duplicated characters.
The first duplicated character is "X" (0x58) which appears at index {1, 7}.

input: "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ", length: 36
The given string has duplicated characters.
The first duplicated character is "0" (0x30) which appears at index {10, 25}.

Mathematica / Wolfram Language

ClearAll[UniqueCharacters]
UniqueCharacters[s_String] := Module[{c, len, good = True},
  c = Characters[s];
  len = Length[c];
  Print[s, " with length ", len];
  Do[
   If[c[[i]] == c[[j]],
    Print["Character ", c[[i]], " is repeated at positions ", i, 
     " and ", j];
    good = False
    ]
   ,
   {i, len - 1},
   {j, i + 1, len}
   ];
  If[good,
   Print["No repeats"];
   True
   ,
   False
   ]
  ]
UniqueCharacters[""]
UniqueCharacters["."]
UniqueCharacters["abcABC"]
UniqueCharacters["XYZ ZYX"]
UniqueCharacters["1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"]
Output:
 with length 0
No repeats
True
. with length 1
No repeats
True
abcABC with length 6
No repeats
True
XYZ ZYX with length 7
Character X is repeated at positions 1 and 7
Character Y is repeated at positions 2 and 6
Character Z is repeated at positions 3 and 5
False
1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ with length 36
Character 0 is repeated at positions 10 and 25
False

Nanoquery

def analyze(s)
        s = str(s)
        println "Examining [" + s + "] which has a length of " + str(len(s)) + ":"

        if len(s) < 2
                println "\tAll characters in the string are unique."
                return
        end

        seen = list()
        for i in range(0, len(s) - 2)
                if s[i] in seen
                        println "\tNot all characters in the string are unique."
                        println "\t'" + s[i] + "' " + format("(0x%x)", ord(s[i])) +\
                                " is duplicated at positions " + str(i + 1) + " and " +\
                                str(s.indexOf(s[i]) + 1)
                        return
                end
                seen.append(s[i])
        end

        println "\tAll characters in the string are unique."
end

tests = {"", ".", "abcABC", "XYZ ZYX", "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"}
for s in tests
        analyze(s)
end
Output:
Examining [] which has a length of 0:
        All characters in the string are unique.
Examining [.] which has a length of 1:
        All characters in the string are unique.
Examining [abcABC] which has a length of 6:
        All characters in the string are unique.
Examining [XYZ ZYX] which has a length of 7:
        Not all characters in the string are unique.
        'Z' (0x5a) is duplicated at positions 5 and 3
Examining [1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ] which has a length of 36:
        Not all characters in the string are unique.
        '0' (0x30) is duplicated at positions 25 and 10

Nim

import unicode, strformat

proc checkUniqueChars(s: string) =

  echo fmt"Checking string ""{s}"":"
  let runes = s.toRunes
  for i in 0..<runes.high:
    let rune = runes[i]
    for j in (i+1)..runes.high:
      if runes[j] == rune:
        echo "The string contains duplicate characters."
        echo fmt"Character {rune} ({int(rune):x}) is present at positions {i+1} and {j+1}."
        echo ""
        return
  echo "All characters in the string are unique."
  echo ""

const Strings = ["",
                 ".",
                 "abcABC",
                 "XYZ ZYX",
                 "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
                 "hétérogénéité",
                 "🎆🎃🎇🎈",
                 "😍😀🙌💃😍🙌",
                 "🐠🐟🐡🦈🐬🐳🐋🐡"]

for s in Strings:
  s.checkUniqueChars()
Output:
Checking string "":
All characters in the string are unique.

Checking string ".":
All characters in the string are unique.

Checking string "abcABC":
All characters in the string are unique.

Checking string "XYZ ZYX":
The string contains duplicate characters.
Character X (58) is present at positions 1 and 7.

Checking string "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ":
The string contains duplicate characters.
Character 0 (30) is present at positions 10 and 25.

Checking string "hétérogénéité":
The string contains duplicate characters.
Character é (e9) is present at positions 2 and 4.

Checking string "🎆🎃🎇🎈":
All characters in the string are unique.

Checking string "😍😀🙌💃😍🙌":
The string contains duplicate characters.
Character 😍 (1f60d) is present at positions 1 and 5.

Checking string "🐠🐟🐡🦈🐬🐳🐋🐡":
The string contains duplicate characters.
Character 🐡 (1f421) is present at positions 3 and 8.

OCaml

Using a map to store characters we've met (as keys) and their first position (as indexes).

module CMap = Map.Make(struct
  type t = char
  let compare = compare
end)

(** Add index as argument to string.fold_left *)
let string_fold_left_i f acc str =
  snd (String.fold_left
    (fun (index, acc) char -> (index+1, f acc index char))
    (0, acc) str)

exception Found of int * int * char

let has_duplicates str =
  try let _ = string_fold_left_i
    (fun map index char ->
      match CMap.find_opt char map with
        | None -> CMap.add char index map
        | Some i -> raise (Found (i,index,char)))
    CMap.empty str
    in Ok ()
  with Found (i,j,c) -> Error (i,j,c)

let printer str =
  Format.printf "%S (len %d) : " str (String.length str);
  match has_duplicates str with
  | Ok () -> Format.printf "No duplicates.\n"
  | Error (i,j,c) -> Format.printf "Duplicate '%c' (%#x) at %d and %d\n" c (int_of_char c) i j

let () =
  printer "";
  printer ".";
  printer "abcABC";
  printer "XYZ ZYX";
  printer "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"
Output:
"" (len 0) : No duplicates.
"." (len 1) : No duplicates.
"abcABC" (len 6) : No duplicates.
"XYZ ZYX" (len 7) : Duplicate 'Z' (0x5a) at 2 and 4
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (len 36) : Duplicate '0' (0x30) at 9 and 24

Perl

use strict;
use warnings;
use feature 'say';
use utf8;
binmode(STDOUT, ':utf8');
use List::AllUtils qw(uniq);
use Unicode::UCD 'charinfo';

for my $str (
    '',
    '.',
    'abcABC',
    'XYZ ZYX',
    '1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ',
    '01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X',
    'Δ👍👨👍Δ',
    'ΔδΔ̂ΔΛ',
) {
    my @S;
    push @S, $1 while $str =~ /(\X)/g;
    printf qq{\n"$str" (length: %d) has }, scalar @S;
    if (@S != uniq @S ) {
        say "duplicated characters:";
        my %P;
        push @{ $P{$S[$_]} }, 1+$_ for 0..$#S;
        for my $k (sort keys %P) {
            next unless @{$P{$k}} > 1;
            printf "'%s' %s (0x%x) in positions: %s\n", $k, charinfo(ord $k)->{'name'}, ord($k), join ', ', @{$P{$k}};
        }
    } else {
        say "no duplicated characters."
    }
}
Output:
"" (length: 0) has no duplicated characters.

"." (length: 1) has no duplicated characters.

"abcABC" (length: 6) has no duplicated characters.

"XYZ ZYX" (length: 7) has duplicated characters:
'X' LATIN CAPITAL LETTER X (0x58) in positions: 1, 7
'Y' LATIN CAPITAL LETTER Y (0x59) in positions: 2, 6
'Z' LATIN CAPITAL LETTER Z (0x5a) in positions: 3, 5

"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (length: 36) has duplicated characters:
'0' DIGIT ZERO (0x30) in positions: 10, 25

"01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X" (length: 39) has duplicated characters:
'0' DIGIT ZERO (0x30) in positions: 1, 11, 26, 38
'X' LATIN CAPITAL LETTER X (0x58) in positions: 35, 39

"Δ👍👨👍Δ" (length: 5) has duplicated characters:
'Δ' GREEK CAPITAL LETTER DELTA (0x394) in positions: 1, 5
'👍' THUMBS UP SIGN (0x1f44d) in positions: 2, 4

"ΔδΔ̂ΔΛ" (length: 5) has duplicated characters:
'Δ' GREEK CAPITAL LETTER DELTA (0x394) in positions: 1, 4

Phix

As with Determine_if_a_string_has_all_the_same_characters#Phix, you can use utf8_to_utf32() when needed.

procedure all_uniq(sequence s)
    string chars = ""
    sequence posns = {},
             multi = {}
    integer lm = 0
    for i=1 to length(s) do
        integer si = s[i],
                k = find(si,chars)
        if k=0 then
            chars &= si
            posns &= {{i}}
        else
            posns[k] &= i
            if length(posns[k])=2 then
                multi &= k
                lm += 1
            end if
        end if      
    end for
    string msg = sprintf("\"%s\" (length %d): ",{s,length(s)}),
           nod = ordinal(lm,true),
           ess = "s"[1..lm>1],
           res = iff(lm=0?"all characters are unique"
                         :sprintf("contains %s duplicate%s:",{nod,ess}))
    printf(1,"%s %s\n",{msg,res})
    res = repeat(' ',length(msg))
    for i=1 to length(multi) do
        integer mi = multi[i],
                ci = chars[mi]
        printf(1,"%s '%c'(#%02x) at %V\n",{res,ci,ci,posns[mi]})
    end for
    printf(1,"\n")
end procedure
 
constant tests = {"",".","abcABC","XYZ ZYX","1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
                  "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X",
                  "   ","2","333","55","tttTTT","tTTTtt","4444 444k"}
papply(tests,all_uniq)
Output:
"" (length 0):  all characters are unique

"." (length 1):  all characters are unique

"abcABC" (length 6):  all characters are unique

"XYZ ZYX" (length 7):  contains three duplicates:
                       'Z'(#5A) at {3,5}
                       'Y'(#59) at {2,6}
                       'X'(#58) at {1,7}

"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (length 36):  contains one duplicate:
                                                     '0'(#30) at {10,25}

"01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X" (length 39):  contains two duplicates:
                                                        '0'(#30) at {1,11,26,38}
                                                        'X'(#58) at {35,39}

"   " (length 3):  contains one duplicate:
                   ' '(#20) at {1,2,3}

"2" (length 1):  all characters are unique

"333" (length 3):  contains one duplicate:
                   '3'(#33) at {1,2,3}

"55" (length 2):  contains one duplicate:
                  '5'(#35) at {1,2}

"tttTTT" (length 6):  contains two duplicates:
                      't'(#74) at {1,2,3}
                      'T'(#54) at {4,5,6}

"tTTTtt" (length 6):  contains two duplicates:
                      'T'(#54) at {2,3,4}
                      't'(#74) at {1,5,6}

"4444 444k" (length 9):  contains one duplicate:
                         '4'(#34) at {1,2,3,4,6,7,8}

The results are effectively printed in order of posns[2], but that can easily be changed, for example by sorting multi before that final print loop.

PicoLisp

(de burn (Lst)
   (let P 0
      (by
         '((A)
            (set A (inc 'P))
            (put A 'P (char A)) )
         group
         Lst ) ) )
(de first (Lst)
   (mini
      '((L)
         (nand
            (cdr L)
            (apply min (mapcar val L)) ) )
      Lst ) )
(de uniq? (Str)
   (let M (first (burn (chop Str)))
      (ifn M
         (prinl Str " (length " (length Str) "): all characters are unique")
         (prin
            Str " (length " (length Str) "): first duplicate character "
            (car M)
            " at positions " )
         (println (mapcar val M)) ) ) )
(uniq?)
(uniq? ".")
(uniq? "abcABC")
(uniq? "XYZ ZYX")
(uniq? "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ")
Output:
 (length 0): all characters are unique
. (length 1): all characters are unique
abcABC (length 6): all characters are unique
XYZ ZYX (length 7): first duplicate character X at positions (1 7)
1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ (length 36): first duplicate character 0 at positions (10 25)

Prolog

report_duplicates(S) :-
	duplicates(S, Dups),		
	format('For value "~w":~n', S),
	report(Dups),
	nl.
	
report(Dups) :-
	maplist(only_one_position, Dups),
	format('    All characters are unique~n').
	
report(Dups) :-
	exclude(only_one_position, Dups, [c(Char,Positions)|_]),
	reverse(Positions, PosInOrder),
	atomic_list_concat(PosInOrder, ', ', PosAsList),
	format('    The character ~w is non unique at ~p~n', [Char, PosAsList]).	
	
only_one_position(c(_,[_])).	
	
duplicates(S, Count) :- 
	atom_chars(S, Chars), 
	char_count(Chars, 0, [], Count).
		
char_count([], _, C, C).
char_count([C|T], Index, Counted, Result) :-
	select(c(C,Positions), Counted, MoreCounted),
	succ(Index, Index1),
	char_count(T, Index1, [c(C,[Index|Positions])|MoreCounted], Result).
char_count([C|T], Index, Counted, Result) :-
	\+ member(c(C,_), Counted),
	succ(Index, Index1),
	char_count(T, Index1, [c(C,[Index])|Counted], Result).
	
test :-	report_duplicates('').
test :-	report_duplicates('.').
test :-	report_duplicates('abcABC').
test :-	report_duplicates('XYZ ZYX').
test :-	report_duplicates('1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ').
Output:
?- forall(test, true).
For value "":
    All characters are unique

For value ".":
    All characters are unique

For value "abcABC":
    All characters are unique

For value "XYZ ZYX":
    The character X is non unique at '0, 6'

For value "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ":
    The character 0 is non unique at '9, 24'

true.

?-

Python

Functional

Defined in terms of itertools.groupby:

'''Determine if a string has all unique characters'''

from itertools import groupby


# duplicatedCharIndices :: String -> Maybe (Char, [Int])
def duplicatedCharIndices(s):
    '''Just the first duplicated character, and
       the indices of its occurrence, or
       Nothing if there are no duplications.
    '''
    def go(xs):
        if 1 < len(xs):
            duplicates = list(filter(lambda kv: 1 < len(kv[1]), [
                (k, list(v)) for k, v in groupby(
                    sorted(xs, key=swap),
                    key=snd
                )
            ]))
            return Just(second(fmap(fst))(
                sorted(
                    duplicates,
                    key=lambda kv: kv[1][0]
                )[0]
            )) if duplicates else Nothing()
        else:
            return Nothing()
    return go(list(enumerate(s)))


# TEST ----------------------------------------------------
# main :: IO ()
def main():
    '''Test over various strings.'''

    def showSample(s):
        return repr(s) + ' (' + str(len(s)) + ')'

    def showDuplicate(cix):
        c, ix = cix
        return repr(c) + (
            ' (' + hex(ord(c)) + ') at ' + repr(ix)
        )

    print(
        fTable('First duplicated character, if any:')(
            showSample
        )(maybe('None')(showDuplicate))(duplicatedCharIndices)([
            '', '.', 'abcABC', 'XYZ ZYX',
            '1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ'
        ])
    )


# FORMATTING ----------------------------------------------

# fTable :: String -> (a -> String) ->
# (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
    '''Heading -> x display function -> fx display function ->
       f -> xs -> tabular string.
    '''
    def go(xShow, fxShow, f, xs):
        ys = [xShow(x) for x in xs]
        w = max(map(len, ys))
        return s + '\n' + '\n'.join(map(
            lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)),
            xs, ys
        ))
    return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
        xShow, fxShow, f, xs
    )


# GENERIC -------------------------------------------------

# Just :: a -> Maybe a
def Just(x):
    '''Constructor for an inhabited Maybe (option type) value.
       Wrapper containing the result of a computation.
    '''
    return {'type': 'Maybe', 'Nothing': False, 'Just': x}


# Nothing :: Maybe a
def Nothing():
    '''Constructor for an empty Maybe (option type) value.
       Empty wrapper returned where a computation is not possible.
    '''
    return {'type': 'Maybe', 'Nothing': True}


# fmap :: (a -> b) -> [a] -> [b]
def fmap(f):
    '''fmap over a list.
       f lifted to a function over a list.
    '''
    return lambda xs: [f(x) for x in xs]


# fst :: (a, b) -> a
def fst(tpl):
    '''First member of a pair.'''
    return tpl[0]


# head :: [a] -> a
def head(xs):
    '''The first element of a non-empty list.'''
    return xs[0] if isinstance(xs, list) else next(xs)


# maybe :: b -> (a -> b) -> Maybe a -> b
def maybe(v):
    '''Either the default value v, if m is Nothing,
       or the application of f to x,
       where m is Just(x).
    '''
    return lambda f: lambda m: v if (
        None is m or m.get('Nothing')
    ) else f(m.get('Just'))


# second :: (a -> b) -> ((c, a) -> (c, b))
def second(f):
    '''A simple function lifted to a function over a tuple,
       with f applied only to the second of two values.
    '''
    return lambda xy: (xy[0], f(xy[1]))


# snd :: (a, b) -> b
def snd(tpl):
    '''Second member of a pair.'''
    return tpl[1]


# swap :: (a, b) -> (b, a)
def swap(tpl):
    '''The swapped components of a pair.'''
    return (tpl[1], tpl[0])


# MAIN ---
if __name__ == '__main__':
    main()
Output:
First duplicated character, if any:
                                     '' (0) -> None
                                    '.' (1) -> None
                               'abcABC' (6) -> None
                              'XYZ ZYX' (7) -> 'X' (0x58) at [0, 6]
'1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ' (36) -> '0' (0x30) at [9, 24]


Or, as an alternative to sorting and grouping, folding a string down to a dictionary with reduce:

'''Determine if a string has all unique characters'''

from functools import reduce


# duplicatedCharIndices :: String -> Maybe (Char, [Int])
def duplicatedCharIndices(s):
    '''Just the first duplicated character, and
       the indices of its occurrence, or
       Nothing if there are no duplications.
    '''
    def go(dct, ic):
        i, c = ic
        return dict(
            dct,
            **{c: dct[c] + [i] if c in dct else [i]}
        )
    duplicates = [
        (k, v) for (k, v)
        in reduce(go, enumerate(s), {}).items()
        if 1 < len(v)
    ]
    return Just(
        min(duplicates, key=compose(head, snd))
    ) if duplicates else Nothing()


# And another alternative here would be to fuse the 1 < len(v)
# filtering, and the min() search for the earliest duplicate,
# down to a single `earliestDuplication` fold:

# duplicatedCharIndices_ :: String -> Maybe (Char, [Int])
def duplicatedCharIndices_(s):
    '''Just the first duplicated character, and
       the indices of its occurrence, or
       Nothing if there are no duplications.
    '''
    def positionRecord(dct, ic):
        i, c = ic
        return dict(
            dct,
            **{c: dct[c] + [i] if c in dct else [i]}
        )

    def earliestDuplication(sofar, charPosns):
        c, indices = charPosns
        return (
            maybe(Just((c, indices)))(
                lambda kxs: Just((c, indices)) if (
                    # Earlier duplication ?
                    indices[0] < kxs[1][0]
                ) else sofar
            )(sofar)
        ) if 1 < len(indices) else sofar

    return reduce(
        earliestDuplication,
        reduce(
            positionRecord,
            enumerate(s),
            {}
        ).items(),
        Nothing()
    )


# TEST ----------------------------------------------------
# main :: IO ()
def main():
    '''Test over various strings.'''

    def showSample(s):
        return repr(s) + ' (' + str(len(s)) + ')'

    def showDuplicate(cix):
        c, ix = cix
        return repr(c) + (
            ' (' + hex(ord(c)) + ') at ' + repr(ix)
        )

    print(
        fTable('First duplicated character, if any:')(
            showSample
        )(maybe('None')(showDuplicate))(duplicatedCharIndices_)([
            '', '.', 'abcABC', 'XYZ ZYX',
            '1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ'
        ])
    )


# FORMATTING ----------------------------------------------

# fTable :: String -> (a -> String) ->
# (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
    '''Heading -> x display function -> fx display function ->
       f -> xs -> tabular string.
    '''
    def go(xShow, fxShow, f, xs):
        ys = [xShow(x) for x in xs]
        w = max(map(len, ys))
        return s + '\n' + '\n'.join(map(
            lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)),
            xs, ys
        ))
    return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
        xShow, fxShow, f, xs
    )


# GENERIC -------------------------------------------------

# Just :: a -> Maybe a
def Just(x):
    '''Constructor for an inhabited Maybe (option type) value.
       Wrapper containing the result of a computation.
    '''
    return {'type': 'Maybe', 'Nothing': False, 'Just': x}


# Nothing :: Maybe a
def Nothing():
    '''Constructor for an empty Maybe (option type) value.
       Empty wrapper returned where a computation is not possible.
    '''
    return {'type': 'Maybe', 'Nothing': True}


# compose :: ((a -> a), ...) -> (a -> a)
def compose(*fs):
    '''Composition, from right to left,
       of a series of functions.
    '''
    return lambda x: reduce(
        lambda a, f: f(a),
        fs[::-1], x
    )


# head :: [a] -> a
def head(xs):
    '''The first element of a non-empty list.'''
    return xs[0] if isinstance(xs, list) else next(xs)


# maybe :: b -> (a -> b) -> Maybe a -> b
def maybe(v):
    '''Either the default value v, if m is Nothing,
       or the application of f to x,
       where m is Just(x).
    '''
    return lambda f: lambda m: v if (
        None is m or m.get('Nothing')
    ) else f(m.get('Just'))


# snd :: (a, b) -> b
def snd(tpl):
    '''Second member of a pair.'''
    return tpl[1]


# MAIN ---
if __name__ == '__main__':
    main()
Output:
First duplicated character, if any:
                                     '' (0) -> None
                                    '.' (1) -> None
                               'abcABC' (6) -> None
                              'XYZ ZYX' (7) -> 'X' (0x58) at [0, 6]
'1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ' (36) -> '0' (0x30) at [9, 24]

Using regular expression

The second part of the pattern uses the '*?' match qualifier, which makes the match "lazy" or "reluctant". '.*' instead of '.*?' would have matched the substring "cocc" instead of "coc" in the first example below. Tested with Python 3.7.

import re

pattern = '(.)' + '.*?' + r'\1'

def find_dup_char(subject):
    match = re.search(pattern, subject)
    if match:
        return match.groups(0)[0], match.start(0), match.end(0)

def report_dup_char(subject):
    dup = find_dup_char(subject)
    prefix = f'"{subject}" ({len(subject)})'
    if dup:
        ch, pos1, pos2 = dup
        print(f"{prefix}: '{ch}' (0x{ord(ch):02x}) duplicates at {pos1}, {pos2-1}")
    else:
        print(f"{prefix}: no duplicate characters")

show = report_dup_char
show('coccyx')
show('')
show('.')
show('abcABC')
show('XYZ ZYX')
show('1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ')
Output:
"coccyx" (6): 'c' (0x63) duplicates at 0, 2
"" (0): no duplicate characters
"." (1): no duplicate characters
"abcABC" (6): no duplicate characters
"XYZ ZYX" (7): 'X' (0x58) duplicates at 0, 6
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (36): '0' (0x30) duplicates at 9, 24

Quackery

  [ over find swap found ]    is has         ( $ c --> b     )

  [ dip [ 0 0 true ]
    dup size 2 < iff
      drop done
    dup size 1 - times
      [ behead 2dup has iff
          [ swap find
            dip not
            2swap 2drop
            i^ tuck + 1+ rot
            0 conclude ] done
        drop ]
    drop ]                    is uniquechars (   $ --> n n b )

  [ dup say 'String "'
    echo$
    say '" has length '
    dup size echo
    say ". "
    dup uniquechars iff
      [ say "There are no duplicated characters."
        drop 2drop ]
    else
      [ rot over peek
        dup say 'The character "'
        emit
        say '" (hex:'
        16 base put
        echo
        base release
        say ") is at positions "
        swap echo
        say " and "
        echo
        say "." ]
    cr ]                       is task        (   $ -->       )

  $ "" task
  $ "." task
  $ "abcABC" task
  $ "XYZ ZYX" task
  $ "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" task
Output:
String "" has length 0. There are no duplicated characters.
String "." has length 1. There are no duplicated characters.
String "abcABC" has length 6. There are no duplicated characters.
String "XYZ ZYX" has length 7. The character "X" (hex:58) is at positions 0 and 6.
String "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" has length 36. The character "0" (hex:30) is at positions 9 and 24.

R

Most of this is adapted from Determine if a string has all the same characters#R.

isAllUnique <- function(string)
{
  strLength <- nchar(string)
  if(length(strLength) > 1)
  {
    #R has a distinction between the length of a string and that of a character vector. It is a common source
    #of problems when coming from another language. We will try to avoid the topic here.
    #For our purposes, let us only say that there is a good reason why we have made
    #isAllUnique(c("foo", "bar") immediately throw an error.
    stop("This task is intended for character vectors with lengths of at most 1.")
  }
  else if(length(strLength) == 0)
  {
    cat("Examining a character vector of length 0.",
        "It is therefore made entirely of unique characters.\n")
    TRUE
  }
  else if(strLength == 0)
  {
    cat("Examining a character vector of length 1, containing an empty string.",
        "It is therefore made entirely of unique characters.\n")
    TRUE
  }
  else if(strLength == 1)
  {
    cat("Examining the string", paste0(sQuote(string), ","),
        "which is of length", paste0(strLength, "."),
        "It is therefore made entirely of unique characters.\n")
    TRUE
  }
  else
  {
    cat("Examining the string", paste0(sQuote(string), ","),
        "which is of length", paste0(strLength, ":"), "\n")
    #strsplit outputs a list. Its first element is the vector of characters that we desire.
    characters <- strsplit(string, "")[[1]]
    #Our use of match is using R's vector recycling rules. Element i is being checked
    #against every other.
    indexesOfDuplicates <- sapply(seq_len(strLength), function(i) match(TRUE, characters[i] == characters[-i], nomatch = -1)) + 1
    firstDuplicateElementIndex <- indexesOfDuplicates[indexesOfDuplicates != 0][1]
    if(is.na(firstDuplicateElementIndex))
    {
      cat("It has no duplicates. It is therefore made entirely of unique characters.\n")
      TRUE
    }
    else
    {
      cat("It has duplicates. ")
      firstDuplicatedCharacter <- characters[firstDuplicateElementIndex]
      cat(sQuote(firstDuplicatedCharacter), "is the first duplicated character. It has hex value",
          sprintf("0x%X", as.integer(charToRaw(firstDuplicatedCharacter))),
          "and is at index", paste0(firstDuplicateElementIndex, "."),
          "\nThis is a duplicate of the character at index",
          paste0(match(firstDuplicateElementIndex, indexesOfDuplicates), "."), "\n")
      FALSE
    }
  }
}

#Tests:
cat("Test: A string of length 0 (an empty string):\n")
cat("Test 1 of 2: An empty character vector:\n")
print(isAllUnique(character(0)))
cat("Test 2 of 2: A character vector containing the empty string:\n")
print(isAllUnique(""))
cat("Test: A string of length 1 which contains .:\n")
print(isAllUnique("."))
cat("Test: A string of length 6 which contains abcABC:\n")
print(isAllUnique("abcABC"))
cat("Test: A string of length 7 which contains XYZ ZYX:\n")
print(isAllUnique("XYZ ZYX"))
cat("Test: A string of length 36 doesn't contain the letter 'oh':\n")
print(isAllUnique("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"))
Output:
Test: A string of length 0 (an empty string):
Test 1 of 2: An empty character vector:
Examining a character vector of length 0. It is therefore made entirely of unique characters.
[1] TRUE
Test 2 of 2: A character vector containing the empty string:
Examining a character vector of length 1, containing an empty string. It is therefore made entirely of unique characters.
[1] TRUE
Test: A string of length 1 which contains .:
Examining the string ‘.’, which is of length 1. It is therefore made entirely of unique characters.
[1] TRUE
Test: A string of length 6 which contains abcABC:
Examining the string ‘abcABC’, which is of length 6: 
It has no duplicates. It is therefore made entirely of unique characters.
[1] TRUE
Test: A string of length 7 which contains XYZ ZYX:
Examining the string ‘XYZ ZYX’, which is of length 7: 
It has duplicates. ‘X’ is the first duplicated character. It has hex value 0x58 and is at index 7. 
This is a duplicate of the character at index 1. 
[1] FALSE
Test: A string of length 36 doesn't contain the letter 'oh':
Examining the string ‘1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ’, which is of length 36: 
It has duplicates. ‘0’ is the first duplicated character. It has hex value 0x30 and is at index 25. 
This is a duplicate of the character at index 10. 
[1] FALSE

Racket

#lang racket

(define (first-non-unique-element.index seq)
  (let/ec ret
    (for/fold ((es (hash))) ((e seq) (i (in-naturals)))
      (if (hash-has-key? es e) (ret (list e (hash-ref es e) i)) (hash-set es e i)))
    #f))

(define (report-if-a-string-has-all-unique-characters str)
  (printf "~s (length ~a): ~a~%" str (string-length str)
          (match (first-non-unique-element.index str)
            [#f "contains all unique characters"]
            [(list e i i′) (format "has character '~a' (0x~a) at index ~a (first seen at ~a)"
                                   e (number->string (char->integer e) 16) i′ i)])))

(module+ main
  (for-each report-if-a-string-has-all-unique-characters
            (list "" "." "abcABC" "XYZ ZYX"
                  "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ")))
Output:
"" (length 0): contains all unique characters
"." (length 1): contains all unique characters
"abcABC" (length 6): contains all unique characters
"XYZ ZYX" (length 7): has character 'Z' (0x5a) at index 4 (first seen at 2)
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (length 36): has character '0' (0x30) at index 24 (first seen at 9)

Raku

(formerly Perl 6)

Works with: Rakudo version 2020.08.1

Raku works with unicode natively and handles combining characters and multi-byte emoji correctly. In the last string, notice the the length is correctly shown as 11 characters and that the delta with a combining circumflex in position 6 is not the same as the deltas without in positions 5 & 9.

  -> $str {
    my $i = 0;
    print "\n{$str.raku} (length: {$str.chars}), has ";
    my %m = $str.comb.Bag;
    if any(%m.values) > 1 {
        say "duplicated characters:";
        say "'{.key}' ({.key.uninames}; hex ordinal: {(.key.ords).fmt: "0x%X"})" ~
        " in positions: {.value.join: ', '}" for %m.grep( *.value > 1 ).sort( *.value[0] );
    } else {
        say "no duplicated characters."
    }
} for
    '',
    '.',
    'abcABC',
    'XYZ ZYX',
    '1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ',
    '01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X',
    '🦋🙂👨‍👩‍👧‍👦🙄ΔΔ̂ 🦋Δ👍👨‍👩‍👧‍👦'
Output:
"" (length: 0), has no duplicated characters.

"." (length: 1), has no duplicated characters.

"abcABC" (length: 6), has no duplicated characters.

"XYZ ZYX" (length: 7), has duplicated characters:
'X' (LATIN CAPITAL LETTER X; hex ordinal: 0x58) in positions: 1, 7
'Y' (LATIN CAPITAL LETTER Y; hex ordinal: 0x59) in positions: 2, 6
'Z' (LATIN CAPITAL LETTER Z; hex ordinal: 0x5A) in positions: 3, 5

"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (length: 36), has duplicated characters:
'0' (DIGIT ZERO; hex ordinal: 0x30) in positions: 10, 25

"01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X" (length: 39), has duplicated characters:
'0' (DIGIT ZERO; hex ordinal: 0x30) in positions: 1, 11, 26, 38
'X' (LATIN CAPITAL LETTER X; hex ordinal: 0x58) in positions: 35, 39

"🦋🙂👨‍👩‍👧‍👦🙄ΔΔ̂ 🦋Δ👍👨‍👩‍👧‍👦" (length: 11), has duplicated characters:
'🦋' (BUTTERFLY; hex ordinal: 0x1F98B) in positions: 1, 8
'👨‍👩‍👧‍👦' (MAN ZERO WIDTH JOINER WOMAN ZERO WIDTH JOINER GIRL ZERO WIDTH JOINER BOY; hex ordinal: 0x1F468 0x200D 0x1F469 0x200D 0x1F467 0x200D 0x1F466) in positions: 3, 11
'Δ' (GREEK CAPITAL LETTER DELTA; hex ordinal: 0x394) in positions: 5, 9

REXX

/*REXX pgm determines if a string is comprised of all unique characters (no duplicates).*/
@.=                                              /*assign a default for the  @.  array. */
parse arg @.1                                    /*obtain optional argument from the CL.*/
if @.1=''  then do;   @.1=                       /*Not specified?  Then assume defaults.*/
                      @.2= .
                      @.3= 'abcABC'
                      @.4= 'XYZ ZYX'
                      @.5= '1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ'
                end

     do j=1;  if j\==1  &  @.j==''  then leave   /*String is null & not j=1?  We're done*/
     say copies('─', 79)                         /*display a separator line  (a fence). */
     say 'Testing for the string (length' length(@.j)"): "   @.j
     say
     dup= isUnique(@.j)
     say 'The characters in the string'   word("are aren't", 1 + (dup>0) )  'all unique.'
     if dup==0  then iterate
     ?= substr(@.j, dup, 1)
     say 'The character '  ?  " ('"c2x(?)"'x)  at position "  dup ,
                                 ' is repeated at position '  pos(?, @.j, dup+1)
     end   /*j*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
isUnique: procedure; parse arg x                          /*obtain the character string.*/
                       do k=1  to length(x) - 1           /*examine all but the last.   */
                       p= pos( substr(x, k, 1), x, k + 1) /*see if the Kth char is a dup*/
                       if p\==0  then return k            /*Find a dup? Return location.*/
                       end   /*k*/
          return 0                                        /*indicate all chars unique.  */
output   when using the internal defaults
───────────────────────────────────────────────────────────────────────────────
Testing for the string (length 0):

The characters in the string are all unique.
───────────────────────────────────────────────────────────────────────────────
Testing for the string (length 1):  .

The characters in the string are all unique.
───────────────────────────────────────────────────────────────────────────────
Testing for the string (length 6):  abcABC

The characters in the string are all unique.
───────────────────────────────────────────────────────────────────────────────
Testing for the string (length 7):  XYZ ZYX

The characters in the string aren't all unique.
The character  X  ('58'x)  at position  1  is repeated at position  7
───────────────────────────────────────────────────────────────────────────────
Testing for the string (length 36):  1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ

The characters in the string aren't all unique.
The character  0  ('30'x)  at position  10  is repeated at position  25

Ring

inputStr = ["",".","abcABC","XYZ ZYX","1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"]
 
for Str in inputStr
    for x = 1 to len(Str)
        for y = x + 1 to len(Str)
            if Str[x] = Str[y]
               char = Str[x]
               ? "Input = " + "'" + Str + "'" + ", length = " + len(Str)
               ? " First duplicate at positions " + x + " and " + y + ", character = " + "'" + char + "'"
               loop 3
            ok
        next
    next
    ? "Input = " + "'" + Str + "'" + ", length = " + len(Str)
    ? " All characters are unique."
next
Output:
Input = '', length = 0
 All characters are unique.
Input = '.', length = 1
 All characters are unique.
Input = 'abcABC', length = 6
 All characters are unique.
Input = 'XYZ ZYX', length = 7
 First duplicate at positions 1 and 7, character = 'X'

Input = '1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ', length = 36
 First duplicate at positions 10 and 25, character = '0'

RPL

Works with: Halcyon Calc version 4.2.7
RPL code Comment
 ≪ → string 
   ≪ "All chars unique" "" 
      1 string SIZE FOR j 
         string j DUP SUB 
         IF DUP2 POS 
         THEN DUP " duplicated at " + 
            string ROT POS →STR + " and " + j →STR +
            ROT DROP SWAP 
            string SIZE 'j' STO 
         ELSE + END NEXT 
      DROP
≫ ≫ 'UNICH?' STO
UNICH? ( "string" --  "report" )
initialize stack
scan string
   extract jth character
   if already seen
      generate report
      .
      .
      exit loop
   else add the char to already seen list
clean stack
.
Input:
≪ { "" "." "abcABC" "XYZ ZYX" "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" } → cases 
   ≪ 1 cases SIZE FOR n cases n GET UNICH? NEXT
≫ ≫ ´TASK’ STO
Output:
5: "All chars unique"
4: "All chars unique"
3: "All chars unique"
2: "Z duplicated at 3 and 5" 
1: "0 duplicated at 10 and 25"

Ruby

strings = ["",
        ".",
        "abcABC",
        "XYZ ZYX",
        "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
        "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X",
        "hétérogénéité",
        "🎆🎃🎇🎈",
        "😍😀🙌💃😍🙌",
        "🐠🐟🐡🦈🐬🐳🐋🐡",]

strings.each do |str|
  seen = {}
  print "#{str.inspect} (size #{str.size}) "
  res = "has no duplicates." #may change
  str.chars.each_with_index do |c,i|
    if seen[c].nil? 
      seen[c] = i
    else
      res =  "has duplicate char #{c} (#{'%#x' % c.ord}) on #{seen[c]} and #{i}."
      break
    end
  end
  puts res
end
Output:
"" (size 0) has no duplicates.
"." (size 1) has no duplicates.
"abcABC" (size 6) has no duplicates.
"XYZ ZYX" (size 7) has duplicate char Z (0x5a) on 2 and 4.
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (size 36) has duplicate char 0 (0x30) on 9 and 24.
"01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X" (size 39) has duplicate char 0 (0x30) on 0 and 10.
"hétérogénéité" (size 13) has duplicate char é (0xe9) on 1 and 3.
"🎆🎃🎇🎈" (size 4) has no duplicates.
"😍😀🙌💃😍🙌" (size 6) has duplicate char 😍 (0x1f60d) on 0 and 4.
"🐠🐟🐡🦈🐬🐳🐋🐡" (size 8) has duplicate char 🐡 (0x1f421) on 2 and 7.

Rust

fn unique(s: &str) -> Option<(usize, usize, char)> {
    s.chars().enumerate().find_map(|(i, c)| {
        s.chars()
            .enumerate()
            .skip(i + 1)
            .find(|(_, other)| c == *other)
            .map(|(j, _)| (i, j, c))
    })
}

fn main() {
    let strings = [
        "",
        ".",
        "abcABC",
        "XYZ ZYX",
        "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
        "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X",
        "hétérogénéité",
        "🎆🎃🎇🎈",
        "😍😀🙌💃😍🙌",
        "🐠🐟🐡🦈🐬🐳🐋🐡",
    ];

    for string in &strings {
        print!("\"{}\" (length {})", string, string.chars().count());
        match unique(string) {
            None => println!(" is unique"),
            Some((i, j, c)) => println!(
                " is not unique\n\tfirst duplicate: \"{}\" (U+{:0>4X}) at indices {} and {}",
                c, c as usize, i, j
            ),
        }
    }
}
Output:
"" (length 0) is unique
"." (length 1) is unique
"abcABC" (length 6) is unique
"XYZ ZYX" (length 7) is not unique
	first duplicate: "X" (U+0058) at indices 0 and 6
"1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" (length 36) is not unique
	first duplicate: "0" (U+0030) at indices 9 and 24
"01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X" (length 39) is not unique
	first duplicate: "0" (U+0030) at indices 0 and 10
"hétérogénéité" (length 13) is not unique
	first duplicate: "é" (U+00E9) at indices 1 and 3
"🎆🎃🎇🎈" (length 4) is unique
"😍😀🙌💃😍🙌" (length 6) is not unique
	first duplicate: "😍" (U+1F60D) at indices 0 and 4
"🐠🐟🐡🦈🐬🐳🐋🐡" (length 8) is not unique
	first duplicate: "🐡" (U+1F421) at indices 2 and 7

Sidef

func index_duplicates(str) {
    gather {
        for k,v in (str.chars.kv) {
            var i = str.index(v, k+1)
            take([k, i]) if (i != -1)
        }
    }
}

var strings = [
    "", ".", "abcABC", "XYZ ZYX",
    "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
    "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X",
    "hétérogénéité", "🎆🎃🎇🎈", "😍😀🙌💃😍🙌",
    "🐠🐟🐡🦈🐬🐳🐋🐡"
]

strings.each {|str|
    print "\n'#{str}' (size: #{str.len}) "
    var dups = index_duplicates(str)
    say "has duplicated characters:" if dups
    for i,j in (dups) {
        say "#{str[i]} (#{'%#x' % str[i].ord}) in positions: #{i}, #{j}"
    }
    say "has no duplicates." if !dups
}
Output:
'' (size: 0) has no duplicates.

'.' (size: 1) has no duplicates.

'abcABC' (size: 6) has no duplicates.

'XYZ ZYX' (size: 7) has duplicated characters:
X (0x58) in positions: 0, 6
Y (0x59) in positions: 1, 5
Z (0x5a) in positions: 2, 4

'1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ' (size: 36) has duplicated characters:
0 (0x30) in positions: 9, 24

'01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X' (size: 39) has duplicated characters:
0 (0x30) in positions: 0, 10
0 (0x30) in positions: 10, 25
0 (0x30) in positions: 25, 37
X (0x58) in positions: 34, 38

'hétérogénéité' (size: 13) has duplicated characters:
é (0xe9) in positions: 1, 3
t (0x74) in positions: 2, 11
é (0xe9) in positions: 3, 7
é (0xe9) in positions: 7, 9
é (0xe9) in positions: 9, 12

'🎆🎃🎇🎈' (size: 4) has no duplicates.

'😍😀🙌💃😍🙌' (size: 6) has duplicated characters:
😍 (0x1f60d) in positions: 0, 4
🙌 (0x1f64c) in positions: 2, 5

'🐠🐟🐡🦈🐬🐳🐋🐡' (size: 8) has duplicated characters:
🐡 (0x1f421) in positions: 2, 7

Tcl

package require Tcl 8.6 ; # For binary encode

array set yesno {1 Yes 2 No}

set test {
    {}
    {.}
    {abcABC}
    {XYZ ZYX}
    {1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ}
    {hétérogénéité}
}

# Loop through test strings
foreach str $test {
    set chars [dict create] ; # init dictionary
    set num_chars 1 ; # In case of empty string

    # Loop through characters in string
    for {set i 0} {$i < [string length $str]} {incr i} {
        set c [string index $str $i] ; # get char at index
        dict lappend chars $c $i ; # add index to a running list for key=char
        set indexes [dict get $chars $c] ; # get the whole running list
        set num_chars [llength $indexes] ; # count the # of indexes
        if {$num_chars > 1} {
            break ; # Found a duplicate, break out of the loop
        }
    }

    # Handle Output
    puts [format "Tested: %38s (len: %2d). All unique? %3s. " \
              "'$str'" [string length $str] $yesno($num_chars)]
    if {$num_chars > 1} {
        puts [format " --> Character '%s' (hex: 0x%s) reappears at indexes: %s." \
                  $c [binary encode hex $c] $indexes]
    }
}
Output:
Tested:                                     '' (len:  0). All unique? Yes.
Tested:                                    '.' (len:  1). All unique? Yes.
Tested:                               'abcABC' (len:  6). All unique? Yes.
Tested:                              'XYZ ZYX' (len:  7). All unique?  No.
 --> Character 'Z' (hex: 0x5a) reappears at indexes: 2 4.
Tested: '1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ' (len: 36). All unique?  No.
 --> Character '0' (hex: 0x30) reappears at indexes: 9 24.
Tested:                        'hétérogénéité' (len: 13). All unique?  No.
 --> Character 'é' (hex: 0xe9) reappears at indexes: 1 3.

V (Vlang)

Translation of: Go
fn analyze(s string) {
    chars := s.runes()
    le := chars.len
    println("Analyzing $s which has a length of $le:")
    if le > 1 {
        for i := 0; i < le-1; i++ {
            for j := i + 1; j < le; j++ {
                if chars[j] == chars[i] {
                    println("  Not all characters in the string are unique.")
                    println("  '${chars[i]}'' (0x${chars[i]:x}) is duplicated at positions ${i+1} and ${j+1}.\n")
                    return
                }
            }
        }
    }
    println("  All characters in the string are unique.\n")
}
 
fn main() {
    strings := [
        "",
        ".",
        "abcABC",
        "XYZ ZYX",
        "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
        "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X",
        "hétérogénéité",
        "🎆🎃🎇🎈",
        "😍😀🙌💃😍🙌",
        "🐠🐟🐡🦈🐬🐳🐋🐡",
    ]
    for s in strings {
        analyze(s)
    }
}
Output:
Analyzing  which has a length of 0:
  All characters in the string are unique.

Analyzing . which has a length of 1:
  All characters in the string are unique.

Analyzing abcABC which has a length of 6:
  All characters in the string are unique.

Analyzing XYZ ZYX which has a length of 7:
  Not all characters in the string are unique.
  'X'' (0x58) is duplicated at positions 1 and 7.

Analyzing 1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ which has a length of 36:
  Not all characters in the string are unique.
  '0'' (0x30) is duplicated at positions 10 and 25.

Analyzing 01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X which has a length of 39:
  Not all characters in the string are unique.
  '0'' (0x30) is duplicated at positions 1 and 11.

Analyzing hétérogénéité which has a length of 13:
  Not all characters in the string are unique.
  'é'' (0xe9) is duplicated at positions 2 and 4.

Analyzing 🎆🎃🎇🎈 which has a length of 4:
  All characters in the string are unique.

Analyzing 😍😀🙌💃😍🙌 which has a length of 6:
  Not all characters in the string are unique.
  '😍'' (0x1f60d) is duplicated at positions 1 and 5.

Analyzing 🐠🐟🐡🦈🐬🐳🐋🐡 which has a length of 8:
  Not all characters in the string are unique.
  '🐡'' (0x1f421) is duplicated at positions 3 and 8.

Wren

Translation of: Go
Library: Wren-fmt
import "./fmt" for Conv, Fmt

var analyze = Fn.new { |s|
    var chars = s.codePoints.toList
    var le = chars.count
    System.print("Analyzing %(Fmt.q(s)) which has a length of %(le):")
    if (le > 1) {
        for (i in 0...le-1) {
            for (j in i+1...le) {
                if (chars[j] == chars[i]) {
                    System.print("  Not all characters in the string are unique.")
                    var c = String.fromCodePoint(chars[i])
                    var hex = "0x" + Conv.hex(chars[i])
                    System.print("  '%(c)' (%(hex)) is duplicated at positions %(i+1) and %(j+1).\n")
                    return
                }
            }
        }
    }
    System.print("  All characters in the string are unique.\n")
}

var strings = [
    "",
    ".",
    "abcABC",
    "XYZ ZYX",
    "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
    "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X",
    "hétérogénéité",
    "🎆🎃🎇🎈",
    "😍😀🙌💃😍🙌",
    "🐠🐟🐡🦈🐬🐳🐋🐡"
]
for (s in strings) analyze.call(s)
Output:
Analyzing "" which has a length of 0:
  All characters in the string are unique.

Analyzing "." which has a length of 1:
  All characters in the string are unique.

Analyzing "abcABC" which has a length of 6:
  All characters in the string are unique.

Analyzing "XYZ ZYX" which has a length of 7:
  Not all characters in the string are unique.
  'X' (0x58) is duplicated at positions 1 and 7.

Analyzing "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ" which has a length of 36:
  Not all characters in the string are unique.
  '0' (0x30) is duplicated at positions 10 and 25.

Analyzing "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X" which has a length of 39:
  Not all characters in the string are unique.
  '0' (0x30) is duplicated at positions 1 and 11.

Analyzing "hétérogénéité" which has a length of 13:
  Not all characters in the string are unique.
  'é' (0xe9) is duplicated at positions 2 and 4.

Analyzing "🎆🎃🎇🎈" which has a length of 4:
  All characters in the string are unique.

Analyzing "😍😀🙌💃😍🙌" which has a length of 6:
  Not all characters in the string are unique.
  '😍' (0x1f60d) is duplicated at positions 1 and 5.

Analyzing "🐠🐟🐡🦈🐬🐳🐋🐡" which has a length of 8:
  Not all characters in the string are unique.
  '🐡' (0x1f421) is duplicated at positions 3 and 8.

XPL0

include xpllib;                 \contains StrLen function

proc    StrUnique(S);           \Show if string has unique chars
char    S;
int     L, I, J, K;
[L:= StrLen(S);
IntOut(0, L);  Text(0, ":       ^"");  Text(0, S);  ChOut(0, ^");  CrLf(0);
for I:= 0 to L-1 do
    for J:= I+1 to L-1 do
        [if S(I) = S(J) then
                [ChOut(0, \tab\ 9);
                for K:= 0 to I do ChOut(0, ^ );
                ChOut(0, ^^);
                for K:= 0 to J-I-2 do ChOut(0, ^ );
                ChOut(0, ^^);
                Text(0, " Duplicate character: ");
                ChOut(0, S(I));
                Text(0, ", hex ");
                SetHexDigits(2);
                HexOut(0, S(I));
                CrLf(0);
                return;
                ];
        ];
Text(0, "       Unique, no duplicates");  CrLf(0);
];

[Text(0, "Length");  CrLf(0);
StrUnique("");
StrUnique(".");
StrUnique("abcABC");
StrUnique("XYZ ZYX");
StrUnique("1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ");
StrUnique("thequickbrownfoxjumps");
]
Output:
Length
0:      ""
        Unique, no duplicates
1:      "."
        Unique, no duplicates
6:      "abcABC"
        Unique, no duplicates
7:      "XYZ ZYX"
         ^     ^ Duplicate character: X, hex 58
36:     "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"
                  ^              ^ Duplicate character: 0, hex 30
21:     "thequickbrownfoxjumps"
             ^            ^ Duplicate character: u, hex 75

zkl

fcn stringUniqueness(str){  // Does not handle Unicode
   sz,unique,uz,counts := str.len(), str.unique(), unique.len(), str.counts();
   println("Length %d: \"%s\"".fmt(sz,str));
   if(sz==uz or uz==1) println("\tAll characters are unique");
   else  // counts is (char,count, char,count, ...)
      println("\tDuplicate: ",
         counts.pump(List,Void.Read,fcn(str,c,n){
            if(n>1){
	       is,z:=List(),-1; do(n){ is.append(z=str.find(c,z+1)) }
	       "'%s' (0x%x)[%s]".fmt(c,c.toAsc(),is.concat(","))
	    }
	    else Void.Skip
	 }.fp(str)).concat(", "));
}
testStrings:=T("", ".", "abcABC", "XYZ ZYX", 
   "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ",
   "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X");
foreach s in (testStrings){ stringUniqueness(s) }
Output:
Length 0: ""
	All characters are unique
Length 1: "."
	All characters are unique
Length 6: "abcABC"
	All characters are unique
Length 7: "XYZ ZYX"
	Duplicate: 'X' (0x58)[0,6], 'Y' (0x59)[1,5], 'Z' (0x5a)[2,4]
Length 36: "1234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ"
	Duplicate: '0' (0x30)[9,24]
Length 39: "01234567890ABCDEFGHIJKLMN0PQRSTUVWXYZ0X"
	Duplicate: '0' (0x30)[0,10,25,37], 'X' (0x58)[34,38]