Before I tell you what you need to do right, let's look at what you're doing wrong:
$char =~ s/.|$/|/g;
The problem here is that both . and | are metacharacters in regular expressions. The | means "or", so you're saying "match . or $". You correctly know that $ means the end of the string, but . means "any one character." So it immediately matches one character, and continues to immediately match one character, each time changing that character to | (metacharacters don't apply in the second half of the s/// expression), then it matches the end of the string and adds a | in there. Or something like that. Basically, not what you want to happen.
$char =~ s/[.|]$/|/g;
Well, inside []s, . and | stop being metacharacters, but [] means "one of these," so this regular expression looks for the character before the end of the string, and if it's either | or ., it changes it to |. Again, not what you want to happen.
$char = tr/.|//d; # and later add |.
tr is the wrong tool for this job. This would delete all . and | characters in your string, expect that you're not using the =~ regex match operator, but the = assignment operator. Definitely not what you want to happen.
What you want is this:
$char =~ s/\.\|$/|/;
We've escaped both the . and the | with a \ so Perl knows "the character after the \ is a literal character with no special meaning*" and matches a literal .| at the end of your string and replaces it with just |.
That said, it sounds like you're kind of new to regular expressions. I'm a big fan of perldoc perlretut, which I think is one of the best (if not the best) introduction to regular expressions in Perl. You should really read it - regexes are a powerful tool in the hands of those who know them, and a powerful headache to those who don't.