Regex (.NET), 74 73 bytes
^(.)* ((.)(?<=(?=\3(?<-4>.*?(?<1>\4))*)(?<-1>\1.*(?=(.)?))* .*))*$(?(1)^)
Try it online! - test cases
Try it on regex101 - try it on your own
This uses a completely different algorithm than my other answer which includes a 70 66 byte .NET version. Like it, this takes the input strings delimited by newline, and works even with zero-length words.
Simply put, it pushes each letter of the first word onto a stack, then goes through each letter of the second word, removing a matching letter from the stack. Iff that completes successfully, and the stack ends up empty, then the two words are anagrams of each other.
What complicates this is that it's a stack, not a random-access array, so to find a matching letter in it, the letters above it need to be moved to a temporary stack, then moved back after the matching letter has been removed.
When interpreting the explanation below, remember that lookbehinds in .NET are evaluated from right to left – so read those from bottom to top, one quantified token at a time. When entering a lookahead inside a lookbehind, go back to reading from top to bottom.
^ # Go to beginning of first word (.)* # Push each letter of first word onto \1 stack ¶ # Go to beginning of second word ( # Begin main loop (.) # \3 = next letter from second word (?<= # Lookbehind (?= # Lookahead \3 # Assert that the last letter popped from the \1 # stack matches \3 (which may make the (?<-1>...) # loop backtrack), and skip it # Transfer \4 stack back onto \1 stack in original order (?<-4> # Pop a letter from the \4 stack as many times as # can be done, each time doing the following: .*? # Skip letters that have already been removed from # the stack in this pass or previous passes (?<1>\4) # Push the letter from \4 back onto the \1 stack )* ) (?<-1> # Pop a letter from the \1 stack as many times as # can be done, each time doing the following: \1 # Match and consume the letter from the \1 stack .* # Skip letters that have already been removed from # the stack in previous passes (?=(.)?) # Push the last letter removed from the \1 stack # onto the \4 stack )* ¶.* # Skip back to the end of the first word ) )* # End main loop $ # Assert end of second word has been reached (?(1)^) # Assert \1 stack has been emptied
aaab, bbba = false\$\endgroup\$