Wednesday, July 30, 2014

Justify alignment

I didn't know that it's called 'Justify alignment'. I decided to implement with C#. Process is simple. Get text and line width, split text into words, make them group of words for each line, print line after padding it with seperator so that start and end of a line will be characters as possible as it can.

namespace Justify
{
  class Program
  {
    /// <summary>
    /// Does justify alignment for given text.
    /// </summary>
    /// <param name="text">string input</param>
    /// <param name="lineWidth">Line width</param>
    /// <returns>List of lines aligned with justify option.</returns>
    static List<string> Justify(string text, int lineWidth)
    {
      var output = new List<string>();

      // 1. Split text into list of words.
      List<List<string>> wordLists = getWords(text, lineWidth);

      // 2. Do justify align per each line.
      foreach (var list in wordLists)
      {
        output.Add(padding(list, lineWidth));
      }

      return output;
    }

    static private List<List<string>> getWords(string text, int lineWidth)
    {
      var output = new List<List<string>>();

      // Split whole text into words.
      string[] words = text.Split(new char[] { ' ' });

      // current width of words with seperator(' ') included.
      int length = 0;
      // List of words to be in a line.
      var wordList = new List<string>();

      for (int i = 0; i < words.Length; ++i)
      {
        // If length of current word is the same or longer than line width,
        if (length == 0 && words[i].Length >= lineWidth)
        {
          // Cut it with line length and put it into word list.
          wordList.Add(words[i].Substring(0, lineWidth));

          // If a word is longer than line width,
          if (words[i].Length > lineWidth)
          {
            // Take the rest of the word and put it into word list back
            // so the rest part would be in next line.
            words[i] = words[i].Substring(lineWidth, words[i].Length - lineWidth);
            i--;
          }
          // Put a line into output list.
          output.Add(wordList);
          wordList = new List<string>();
        }
        // If current line can't contain current word,
        // 1 for seperator ' '
        else if (length + 1 + words[i].Length > lineWidth)
        {
          // pub a line into output list.
          output.Add(wordList);
          // Prepare a new line and reset counter.
          wordList = new List<string>();
          length = 0;
          i--;
        }
        // Else, put a word and increase counter.
        else
        {
          wordList.Add(words[i]);
          length += words[i].Length + 1;
        }
      }

      return output;
    }

    // This does justify. For example, if words ["How", "are", "you"]
    // and line width 15 is given, output will be
    // 123456789012345 <- index
    // How   are   you
    static private string padding(List<string> wordList, int lineWidth)
    {
      // Return empty string if empty list is given.
      if (wordList.Count == 0)
        return string.Empty;

      int i = 0;
      int length = 0;

      // Length is sum of all words length in the list.
      foreach (var word in wordList)
      {
        length += word.Length;
      }

      // Here we append seperator to all words in the list
      // until length is as same as lineWidth.
      while (length < lineWidth)
      {
        if (i == 0 || i != wordList.Count - 1)
        {
          wordList[i] = wordList[i] + " ";
          length++;
        }
        i = (i + 1) % wordList.Count;
      }

      return string.Join<string>("", wordList);
    }

    static void Main(string[] args)
    {
      string text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

      var output = Justify(text, 30);
      foreach (var line in output)
          Console.WriteLine(line);
    }
  }
}
Then the output is,
Lorem  ipsum  dolor  sit amet,
consectetur  adipisicing elit,
sed    do    eiusmod    tempor
incididunt    ut   labore   et
dolore  magna  aliqua. Ut enim
ad  minim veniam, quis nostrud
exercitation  ullamco  laboris
nisi  ut aliquip ex ea commodo
consequat.   Duis  aute  irure
dolor   in   reprehenderit  in
voluptate  velit  esse  cillum
dolore    eu    fugiat   nulla
pariatur.    Excepteur    sint
occaecat     cupidatat     non
proident,  sunt  in  culpa qui
officia  deserunt  mollit anim