In general, the rule is that you should decode text coming from an external source, and encode text being sent to en external sink. In your case you are fetching what looks like UTF-8-encoded data from a database, so you should be decoding it as such. But it looks like it has been partially decoded. Take a look at this program
use utf8;
use strict;
use warnings;
use feature 'say';
my $xx = 'أخلاقيات الأعمال الموضوع';
my $yy = 'أخلاقيات الأعمال الموضوع';
utf8::encode($yy);
say length $xx;
say join ' ', map { sprintf '%04X', ord } split //, $xx;
say length $yy;
say join ' ', map { sprintf '%04X', ord } split //, $yy;
output
46
00D8 00A3 00D8 00AE 00D9 201E 00D8 00A7 00D9 201A 00D9 0160 00D8 00A7 00D8 00AA 0020 00D8 00A7 00D9 201E 00D8 00A3 00D8 00B9 00D9 2026 00D8 00A7 00D9 201E 0020 00D8 00A7 00D9 201E 00D9 2026 00D9 02C6 00D8 00B6 00D9 02C6 00D8 00B9
46
00D8 00A3 00D8 00AE 00D9 0084 00D8 00A7 00D9 0082 00D9 008A 00D8 00A7 00D8 00AA 0020 00D8 00A7 00D9 0084 00D8 00A3 00D8 00B9 00D9 0085 00D8 00A7 00D9 0084 0020 00D8 00A7 00D9 0084 00D9 0085 00D9 0088 00D8 00B6 00D9 0088 00D8 00B9
This shows the Unicode code points for each character in the string you are fetching directly from the database, and the Arabic text that it should represent encoded in UTF-8 bytes. As you can see, everything matches nicely except for the occasional values between 0x82 and 0x8A, which are replaced in the database text by wide other wide Unicode characters like this
0082 => 201A,
0084 => 201E,
0085 => 2026,
0088 => 02C6,
008A => 0160,
It's clear that what you are retrieving from your database is supposed to be UTF-8-encoded text, so it should be nothing but byte values, so I'm struggling to understand what those wide characters are doing in there
So the short answer is that you should use Encode and decode_utf8 the strings that you fetch from the database. But those wide characters will break that approach so you need to find out why you're getting them
I suggest you use the line from my program that dumps a string in hex values, and apply it directly after the string is pulled from the database.
say join ' ', map { sprintf '%04X', ord } split //, $value;
That way we can see what is happening first-hand. As it is there is a lot of encoding/decoding going on between your program, via the Stack Overflow server to my desktop, and any of those stages may be the culprit