Clever way to append 's' for plural form in .Net (syntactic sugar)

前端 未结 14 1624
抹茶落季
抹茶落季 2021-01-30 06:53

I want to be able to type something like:

Console.WriteLine(\"You have {0:life/lives} left.\", player.Lives);

instead of

Consol         


        
相关标签:
14条回答
  • 2021-01-30 07:20

    For C# 6.0 onwards, you can use Interpolated Strings to do this tricks.

    Example:

        Console.WriteLine("\n --- For REGULAR NOUNS --- \n");
        {
            int count1 = 1;
            Console.WriteLine($"I have {count1} apple{(count1 == 1 ? "" : "s")}.");
            int count2 = 5;
            Console.WriteLine($"I have {count2} apple{(count2 == 1 ? "" : "s")}.");
        }
    
        Console.WriteLine("\n --- For IRREGULAR NOUNS --- \n");
        {
            int count1 = 1;
            Console.WriteLine($"He has {count1} {(count1 == 1 ? "leaf" : "leaves")}.");
            int count2 = 5;
            Console.WriteLine($"He has {count2} {(count2 == 1 ? "leaf" : "leaves")}.");
        }
    

    Output:

     --- For REGULAR NOUNS --- 
    
    I have 1 apple.
    I have 5 apples.
    
     --- For IRREGULAR NOUNS --- 
    
    He has 1 leaf.
    He has 5 leaves.
    

    You can play around on my .NET Fiddle.
    For more details, go to Interpolated String documentation.

    0 讨论(0)
  • 2021-01-30 07:20

    Looking at how strings are typically written that account for simultaneous single and multiple values, e.g.

    "Expected {0} file(s), but found {1} file(s)."

    The approach I took was to keep the same string, but add some parsing to determine whether the (s) should be removed completely, or to keep the s inside the round brackets. For irregular words, a slash can separate the singular and plural form.

    Other examples:

    • "Had {0:n2} child(ren)".Pluralize(1.0) => "Had 1.00 child"
    • "Had {0} cherry(ies)".Pluralize(2) => "Had 2 cherries"
    • "Had {0} calf/calves".Pluralize(1) => "Had 1 calf"
    • "Had {0} son(s)-in-law".Pluralize(2) => "Had 2 sons-in-law"
    • "Had {0} able seaman/seamen".Pluralize(1) => "Had 1 able seaman"
    • "Had {0} sheep, {1} goat(s)".Pluralize(1, 2) => "Had 1 sheep, 2 goats"
    ///<summary>
    /// Examples:
    /// "{0} file(s)".Pluralize(1); -> "1 file"
    /// "{0} file(s)".Pluralize(2); -> "2 files"
    ///</summary>
    public static String Pluralize(this String s, params Object[] counts) {
        String[] arr = s.Split(new [] { ' ' }, StringSplitOptions.None);
        for (int i = 0; i < arr.Length; i++) {
            String t = arr[i];
            if (t.Length == 0 || t[0] != '{' || t[t.Length - 1] != '}')
                continue;
    
            int w = 1;
            while (w < t.Length) {
                char c = t[w];
                if (c < '0' || c > '9')
                    break;
                w++;
            }
    
            if (w == 1)
                continue;
    
            int n = int.Parse(t.Substring(1, w-1));
            if (n >= counts.Length)
                continue;
    
            Object o = counts[n];
            if (o == null)
                continue;
    
            bool isSingle = false;
            if (o is int)
                isSingle = 1 == (int) o;
            else if (o is double)
                isSingle = 1 == (double) o;
            else if (o is float)
                isSingle = 1 == (float) o;
            else if (o is decimal)
                isSingle = 1 == (decimal) o;
            else if (o is byte)
                isSingle = 1 == (byte) o;
            else if (o is sbyte)
                isSingle = 1 == (sbyte) o;
            else if (o is short)
                isSingle = 1 == (short) o;
            else if (o is ushort)
                isSingle = 1 == (ushort) o;
            else if (o is uint)
                isSingle = 1 == (uint) o;
            else if (o is long)
                isSingle = 1 == (long) o;
            else if (o is ulong)
                isSingle = 1 == (ulong) o;
            else
                continue;
    
            for (int j = i + 1; j < arr.Length && j < i + 4; j++) {
                String u = arr[j];
                if (u.IndexOf('{') >= 0)
                    break; // couldn't find plural word and ran into next token
    
                int b1 = u.IndexOf('(');
                int b2 = u.IndexOf(')', b1 + 1);
                if (b1 >= 0 && b2 >= 0) {
                    String u1 = u.Substring(0, b1);
                    String u2 = u.Substring(b2+1);
                    char last = (u1.Length > 0 ? u1[u1.Length - 1] : ' ');
                    String v = (isSingle ? "" : u.Substring(b1+1, (b2 - b1) - 1));
                    if ((last == 'y' || last == 'Y') && String.Compare(v, "ies", true) == 0)
                        u1 = u1.TrimEnd('y', 'Y');
    
                    arr[j] = u1 + v + u2;
                    break;
                }
                int s1 = u.IndexOf('/');
                if (s1 >= 0) {
                    arr[j] = (isSingle ? u.Substring(0, s1) : u.Substring(s1 + 1));
                    break;
                }
            }
        }
    
        s = String.Join(" ", arr);
        s = String.Format(s, counts);
        return s;
    }
    
    0 讨论(0)
  • 2021-01-30 07:22
    string message = string.format("You have {0} left.", player.Lives == 1 ? "life" : "lives");
    

    Of course this assumes that you have a finite number of values to pluralize.

    0 讨论(0)
  • 2021-01-30 07:23

    You may checkout the PluralizationService class which is part of the .NET 4.0 framework:

    string lives = "life";
    if (player.Lives != 1)
    {
        lives = PluralizationService
            .CreateService(new CultureInfo("en-US"))
            .Pluralize(lives);
    }
    Console.WriteLine("You have {0} {1} left", player.Lives, lives);
    

    It is worth noting that only English is supported for the moment. Warning, this don't work on the Net Framework 4.0 Client Profile!

    You could also write an extension method:

    public static string Pluralize(this string value, int count)
    {
        if (count == 1)
        {
            return value;
        }
        return PluralizationService
            .CreateService(new CultureInfo("en-US"))
            .Pluralize(value);
    }
    

    And then:

    Console.WriteLine(
        "You have {0} {1} left", player.Lives, "life".Pluralize(player.Lives)
    );
    
    0 讨论(0)
  • 2021-01-30 07:24

    I did a little bit of work with PluralizationService and came up with. I just made the PluralizationService static for performance and combined all.

    Reference System.Data.Entity.Design

      using System.Data.Entity.Design.PluralizationServices;
      using System.Reflection;
    
      public static class Strings
      {
        private static PluralizationService pluralizationService = PluralizationService.CreateService(System.Globalization.CultureInfo.CurrentUICulture);
        public static string Pluralize(this MemberInfo memberInfo)//types, propertyinfos, ect
        {
          return Pluralize(memberInfo.Name.StripEnd());
        }
    
        public static string Pluralize(this string name)
        {
          return pluralizationService.Pluralize(name); // remove EF type suffix, if any
        }
    
        public static string StripEnd(this string name)
        {
          return name.Split('_')[0];
        }
      }
    
    0 讨论(0)
  • 2021-01-30 07:24

    I am using this extension method with .NET 4.6

    public static string Pluralize(this string @string)
    {
         if (string.IsNullOrEmpty(@string)) return string.Empty;
    
         var service = new EnglishPluralizationService();
    
         return service.Pluralize(@string);
    }
    
    0 讨论(0)
提交回复
热议问题