Parameteriserede tekstmønstre

I mit arbejde med websites har jeg til tider haft behov for at kunne vise tekster overfor brugeren, hvor der indgik værdier eller kvantificeringer. Dette har ofte indvirkning på formen af teksten (entals- kontra flertalsformer). Dette kan give en udfordring med antallet af tekster man skal vedligeholde, alternativt den logik der skal indarbejdes i siderne, for at håndtere dette.

Derfor har jeg (inspireret af en artikel jeg, for længe siden, læste om emnet, og desværre ikke kan finde igen), udarbejdet et regelsæt for hvordan man kan styre de mest almindelige formændringer i tekst ved simpelthen at definere et tekstmønster i stedet for den endelige tekst.

Formatet

tal := {0-9}1-n

felt := "{" + <tal> + "}"

operator := "!" | "=" | "<" | ">"

! (operator) := forskellig fra

= (operator) := lig med

< (operator) := mindre end

> (operator) := større end

tekst := et eller flere karakterer undtagen ":"

værdi := <tal>

mønster := "[#" + <tal> + <operator> + <værdi> + ":" + <tekst> + {"|" + <operator> + <værdi> + ":" + <tekst>} + "]"

Eksempel:

"Der blev fundet {0} sag[#0!1:er] i {1} mappe[#1!1:r]"

Hvor 1 fundet sag i 1 mappe vil resultere i flg. tekst:

"Der blev fundet 1 sag i 1 mappe"

Med 2 fundne sager i 1 mappe vil teksten se således ud:

"Der blev fundet 2 sager i 1 mappe"

og så fremdeles...

Konkretisering af konceptet

Med denne regel kan man så påbegynde implementeringen af en funktion til at håndtere dette. Jeg har lavet et par implementering, dels i JavaScript, dels i C#.

I C#-versionen har jeg så lavet et par extension-metoder til string-objektet, således man kan ændre formen på en given streng. Metoden kalder jeg Parameters og den har formatet:

public static class MyExtensions
{
  public static string Parameters(
      this string val, 
      params object[] args
    )
  {
    var parser = new PatternParser();
    return String.Format(parser.Parse(val, args), args);
  }

  public static int ToInt(this string val)
  {
    var i = 0;
    int.TryParse(val, out i);
    return i;
  }

  public static bool IsNumeric(this string val)
  {
    var i = 0;
    return int.TryParse(val, out i);
  }
}

Der er også defineret 2 andre extension-metoder til strings, som benyttes i koden nedenfor.

Eksempel:

"{0} sag[#0!1:er] i {1} mappe[#1!1:r]".Parameters(1,2)

Parametrene kan naturligvis være variable og strengen kan f.eks. komme fra en resursefil, eller en database.

Parseren

Implementeringen af parseren ser således ud:

public class PatternParser
{
  private static readonly Regex re = 
      new Regex(@"\[\#(\d+)((([\=\!\])(.*?)\:(.*?))(?:\|*))*\]");

  public string Parse(string text, object[] parameters)
  {
    return re.Replace(text, m =>
    {
       var fieldIndex = int.Parse(m.Groups[1].Captures[0].Value);
       var fieldValue = int.Parse((string)parameters[fieldIndex]);

       for (int c = 0; c < m.Groups[2].Captures.Count; c++)
       {
          var compareValue = int.Parse(m.Groups[5].Captures[c].Value);

          if (Comparer(
                fieldValue, 
                m.Groups[4].Captures[c].Value, 
                compareValue))
            return m.Groups[6].Captures[c].Value;
       }
       return "";
    });
  }

  private bool Comparer(int a, string operatorValue, int b)
  {
    switch (operatorValue)
    {
      case "=": return a == b;
      case "!": return a != b;
      case "<": return a < b;
      case ">": return a > b;
    }

    return false;
  }
}

Den kan med stor sandsynlighed gøres meget fixere, men betragt denne udgave som et proof of concept og leg selv med optimeringen :-)

Hvad kan man så bruge dette til?

Som nævnt kan man bruge det til at styre former på tekster og det kan med fordel bruges ifm. sprogstyring af et system, dvs. hvor et system skal præsenteres i flere forskellige sprog. Dette er interessant, da sprog har forskellige ordstillinger ligesom der er stor forskel på, hvordan entals- og flertalsendelser styres. Nogle sprog har specifikke endelser for 1, 2, 3, 4, 5 af en ting, hvor vi i det danske sprog kun skelner mellem ental og flertal. Disse regler kan hjælpe med at styre disse tekster uden at ændre på det input strengen skal have der hvor teksten skal præsenteres.

Se også

Jeg har leget lidt med tankerne på Eksperten.dk, som er sammenfattet i en guide (dog med udgangspunkt i flersprogstrying).

Comment