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

前端 未结 14 1659
抹茶落季
抹茶落季 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

    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"
    ///
    /// Examples:
    /// "{0} file(s)".Pluralize(1); -> "1 file"
    /// "{0} file(s)".Pluralize(2); -> "2 files"
    ///
    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;
    }
    

提交回复
热议问题