Is there better way to read values in a string using for loop in dart language

Issue

I am trying to write a code that ask the user for a string and print out whether this string is a palindrome or not.

When code is executed it directly goes to the print statement, the for loop doesn’t into the string and compare the values.

  print("Enter a word to check for palindrome: ");
  String word = stdin.readLineSync()!;
  List<String> palindrome = [word];
  var flag = 0;

  //var len = palindrome.length;

 for (int i = 0; i < palindrome.length; i++) {
    if (palindrome[i] != palindrome[palindrome.length - i - 1]) {
      flag = 1;
      break;
    }
  }

  if (flag == 0) 
  {
    print("$palindrome is palindrome.");
  } else 
  {
    print("$palindrome is not palindrome.");
  }

Solution

Your problem here is that you write:

List<String> palindrome = [word];

then check whether palindrome is a palindrome as a list of elements. It is, since it has only one element, a word which is equal to itself. You never check whether word is a palindrome.

You likely want to whether check the individual characters of the string forms a palindrome instead.
If you change that line to:

String palindrome = word;

then your code will do that.

However, for anything other than an early coding exercise, that approach is too naïve to work in the real world where not all letters are ASCII and not all characters are represented by a single code unit.

The issue with using just the code units is that a string like "😂", aka. "\u{1f602}", should be a palindrome (it contains only one "character"), but the actual string representation is "\uD83d\uDE02", which is not a palindrome at the code-unit level (and swapping the code units is not valid UTF-16).
So, to recognize that, you must treat those two code units as one character.

At the very least, I’d use the runes getter of String to get access to the code points and whether check those form a palindrome. Then the result will still be correct if the string contains simple non-basic multilingual plane characters, which are represented in Dart by two code units:

var r1 = word.runes.iterator;
var r2 = word.runes.iterator..reset(word.length);
while (r1.moveNext() && r2.movePrevious()) {
  if (r1.rawIndex >= r2.rawIndex) break; // Reached the middle.
  if (r1.current != r2.current) {
    flag = 1;
    break;
  }
}

Preferably, for real world text, I would recommend using the characters package to access the grapheme clusters of the text, which can consists of multiple code points.

The same problem applies: The string "🏳️‍🌈" seems like one character and therefore a palindrome, but really it’s a "🏳️\u200D🌈" (white flag, zero-width-joiner, rainbow) sequence, just like many other emojis are created from multiple parts.
The characters package will recognize the rainbow flag as one "character".

import "package:characters/characters.dart";
...
  var r1 = words.characters.iterator;
  var r2 = words.characters.iteratorAtEnd;
  while (r1.moveNext() && r2.moveBack()) {
    if (r1.stringBeforeLength >= r2.stringBeforeLength) {
      break; // Reached the middle.
    }
    if (r1.current != r2.current) {
      flag = 1;
      break;
    }
  }

You can still run into issues with Unicode normalization.
The string "éé" looks like a palindrome, but it is really "ée\u0301", which contains two different representations of the same accented e character, one as a single character, and one as an e with a combining accent after it.
The characters package will report those as different sequences of code points, and not know that they represent the same character.

Answered By – lrn

Answer Checked By – Clifford M. (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *