命名为String.Format,可能吗?

发布于 2024-07-25 01:08:58 字数 377 浏览 7 评论 0原文

我想使用 {title} 代替 {0} {1} 等。 然后以某种方式填充该数据(下面我使用了字典)。 此代码无效并引发异常。 我想知道我是否可以做一些与我想要的类似的事情。 使用 {0 .. N} 不是问题。 我只是好奇而已。

Dictionary<string, string> d = new Dictionary<string, string>();
d["a"] = "he";
d["ba"] = "llo";
d["lol"] = "world";
string a = string.Format("{a}{ba}{lol}", d);

Instead of using {0} {1}, etc. I want to use {title} instead. Then fill that data in somehow (below I used a Dictionary). This code is invalid and throws an exception. I wanted to know if i can do something similar to what i want. Using {0 .. N} is not a problem. I was just curious.

Dictionary<string, string> d = new Dictionary<string, string>();
d["a"] = "he";
d["ba"] = "llo";
d["lol"] = "world";
string a = string.Format("{a}{ba}{lol}", d);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

冰火雁神 2024-08-01 01:08:58

不,但是这个扩展方法可以做到

static string FormatFromDictionary(this string formatString, Dictionary<string, string> valueDict) 
{
    int i = 0;
    StringBuilder newFormatString = new StringBuilder(formatString);
    Dictionary<string, int> keyToInt = new Dictionary<string,int>();
    foreach (var tuple in valueDict)
    {
        newFormatString = newFormatString.Replace("{" + tuple.Key + "}", "{" + i.ToString() + "}");
        keyToInt.Add(tuple.Key, i);
        i++;                    
    }
    return String.Format(newFormatString.ToString(), valueDict.OrderBy(x => keyToInt[x.Key]).Select(x => x.Value).ToArray());
}

No, but this extension method will do it

static string FormatFromDictionary(this string formatString, Dictionary<string, string> valueDict) 
{
    int i = 0;
    StringBuilder newFormatString = new StringBuilder(formatString);
    Dictionary<string, int> keyToInt = new Dictionary<string,int>();
    foreach (var tuple in valueDict)
    {
        newFormatString = newFormatString.Replace("{" + tuple.Key + "}", "{" + i.ToString() + "}");
        keyToInt.Add(tuple.Key, i);
        i++;                    
    }
    return String.Format(newFormatString.ToString(), valueDict.OrderBy(x => keyToInt[x.Key]).Select(x => x.Value).ToArray());
}
我的影子我的梦 2024-08-01 01:08:58

查一下这个,支持格式化:

    public static string StringFormat(string format, IDictionary<string, object> values)
    {
        var matches = Regex.Matches(format, @"\{(.+?)\}");
        List<string> words = (from Match matche in matches select matche.Groups[1].Value).ToList();

        return words.Aggregate(
            format,
            (current, key) =>
                {
                    int colonIndex = key.IndexOf(':');
                    return current.Replace(
                        "{" + key + "}",
                        colonIndex > 0
                            ? string.Format("{0:" + key.Substring(colonIndex + 1) + "}", values[key.Substring(0, colonIndex)])
                            : values[key] == null ? string.Empty : values[key].ToString());
                });
    }

使用方法:

string format = "{foo} is a {bar} is a {baz} is a {qux:#.#} is a really big {fizzle}";
var dictionary = new Dictionary<string, object>
    {
        { "foo", 123 },
        { "bar", true },
        { "baz", "this is a test" },
        { "qux", 123.45 },
        { "fizzle", DateTime.Now }
    };
StringFormat(format, dictionary)

        

Check this one, it supports formating:

    public static string StringFormat(string format, IDictionary<string, object> values)
    {
        var matches = Regex.Matches(format, @"\{(.+?)\}");
        List<string> words = (from Match matche in matches select matche.Groups[1].Value).ToList();

        return words.Aggregate(
            format,
            (current, key) =>
                {
                    int colonIndex = key.IndexOf(':');
                    return current.Replace(
                        "{" + key + "}",
                        colonIndex > 0
                            ? string.Format("{0:" + key.Substring(colonIndex + 1) + "}", values[key.Substring(0, colonIndex)])
                            : values[key] == null ? string.Empty : values[key].ToString());
                });
    }

How to use:

string format = "{foo} is a {bar} is a {baz} is a {qux:#.#} is a really big {fizzle}";
var dictionary = new Dictionary<string, object>
    {
        { "foo", 123 },
        { "bar", true },
        { "baz", "this is a test" },
        { "qux", 123.45 },
        { "fizzle", DateTime.Now }
    };
StringFormat(format, dictionary)

        
后eg是否自 2024-08-01 01:08:58

您可以实现自己的:

public static string StringFormat(string format, IDictionary<string, string> values)
{
    foreach(var p in values)
        format = format.Replace("{" + p.Key + "}", p.Value);
    return format;
}

You can implement your own:

public static string StringFormat(string format, IDictionary<string, string> values)
{
    foreach(var p in values)
        format = format.Replace("{" + p.Key + "}", p.Value);
    return format;
}
江南烟雨〆相思醉 2024-08-01 01:08:58

现在可以

使用 C# 6.0 的插值字符串,您可以执行以下操作:

string name = "John";
string message = $"Hi {name}!";
//"Hi John!"

It's possible now

With Interpolated Strings of C# 6.0 you can do this:

string name = "John";
string message = $"Hi {name}!";
//"Hi John!"
一袭水袖舞倾城 2024-08-01 01:08:58
static public class StringFormat
{
    static private char[] separator = new char[] { ':' };
    static private Regex findParameters = new Regex(
        "\\{(?<param>.*?)\\}",
        RegexOptions.Compiled | RegexOptions.Singleline);

    static string FormatNamed(
        this string format,
        Dictionary<string, object> args)
    {
        return findParameters.Replace(
            format,
            delegate(Match match)
            {
                string[] param = match.Groups["param"].Value.Split(separator, 2);

                object value;
                if (!args.TryGetValue(param[0], out value))
                    value = match.Value;

                if ((param.Length == 2) && (param[1].Length != 0))
                    return string.Format(
                        CultureInfo.CurrentCulture,
                        "{0:" + param[1] + "}",
                        value);
                else
                    return value.ToString();
            });
    }
}

比其他扩展方法涉及更多一点,但这也应该允许在它们上使用非字符串值和格式模式,因此在您的原始示例中:

Dictionary<string, object> d = new Dictionary<string, object>();
d["a"] = DateTime.Now;
string a = string.FormatNamed("{a:yyyyMMdd-HHmmss}", d);

也可以工作...

static public class StringFormat
{
    static private char[] separator = new char[] { ':' };
    static private Regex findParameters = new Regex(
        "\\{(?<param>.*?)\\}",
        RegexOptions.Compiled | RegexOptions.Singleline);

    static string FormatNamed(
        this string format,
        Dictionary<string, object> args)
    {
        return findParameters.Replace(
            format,
            delegate(Match match)
            {
                string[] param = match.Groups["param"].Value.Split(separator, 2);

                object value;
                if (!args.TryGetValue(param[0], out value))
                    value = match.Value;

                if ((param.Length == 2) && (param[1].Length != 0))
                    return string.Format(
                        CultureInfo.CurrentCulture,
                        "{0:" + param[1] + "}",
                        value);
                else
                    return value.ToString();
            });
    }
}

A little more involved than the other extension method, but this should also allow non-string values and formatting patterns used on them, so in your original example:

Dictionary<string, object> d = new Dictionary<string, object>();
d["a"] = DateTime.Now;
string a = string.FormatNamed("{a:yyyyMMdd-HHmmss}", d);

Will also work...

赏烟花じ飞满天 2024-08-01 01:08:58

自 C# 6 发布以来,您可以使用 字符串插值功能

解决您问题的代码:

string a = $"{d["a"]}{d["ba"]}{d["lol"]}";

Since C# 6 released you are able to use String Interpolation feature

Code that solves your question:

string a = $"{d["a"]}{d["ba"]}{d["lol"]}";
っ左 2024-08-01 01:08:58

为什么要有字典? 这是不必要的并且过于复杂。 一个简单的名称/值对的二维数组也可以工作:

public static string Format(this string formatString, string[,] nameValuePairs)
{
    if (nameValuePairs.GetLength(1) != 2)
    {
        throw new ArgumentException("Name value pairs array must be [N,2]", nameof(nameValuePairs));
    }
    StringBuilder newFormat = new StringBuilder(formatString);
    int count = nameValuePairs.GetLength(0);
    object[] values = new object[count];
    for (var index = 0; index < count; index++)
    {
        newFormat = newFormat.Replace(string.Concat("{", nameValuePairs[index,0], "}"), string.Concat("{", index.ToString(), "}"));
        values[index] = nameValuePairs[index,1];
    }
    return string.Format(newFormat.ToString(), values);
}

使用以下命令调用上面的

string format = "{foo} = {bar} (really, it's {bar})";
string formatted = format.Format(new[,] { { "foo", "Dictionary" }, { "bar", "unnecessary" } });

结果:“Dictionary =不必要(实际上,它是不必要的)”

Why a Dictionary? It's unnecessary and overly complicated. A simple 2 dimensional array of name/value pairs would work just as well:

public static string Format(this string formatString, string[,] nameValuePairs)
{
    if (nameValuePairs.GetLength(1) != 2)
    {
        throw new ArgumentException("Name value pairs array must be [N,2]", nameof(nameValuePairs));
    }
    StringBuilder newFormat = new StringBuilder(formatString);
    int count = nameValuePairs.GetLength(0);
    object[] values = new object[count];
    for (var index = 0; index < count; index++)
    {
        newFormat = newFormat.Replace(string.Concat("{", nameValuePairs[index,0], "}"), string.Concat("{", index.ToString(), "}"));
        values[index] = nameValuePairs[index,1];
    }
    return string.Format(newFormat.ToString(), values);
}

Call the above with:

string format = "{foo} = {bar} (really, it's {bar})";
string formatted = format.Format(new[,] { { "foo", "Dictionary" }, { "bar", "unnecessary" } });

Results in: "Dictionary = unnecessary (really, it's unnecessary)"

み青杉依旧 2024-08-01 01:08:58
public static string StringFormat(this string format, IDictionary<string, object> values)
{
    return Regex.Matches(format, @"\{(?!\{)(.+?)\}")
            .Select(m => m.Groups[1].Value)
            .Aggregate(format, (current, key) =>
            {
                string[] splits = key.Split(":");
                string replacement = splits.Length > 1
                    ? string.Format($"{{0:{splits[1]}}}", values[splits[0]])
                    : values[key].ToString();
                return Regex.Replace(current, "(.|^)("+ Regex.Escape($"{{{key}}}")+")(.|$)", 
                                     m => m.Groups[1].ToString() == "{" && m.Groups[3].ToString() == "}"
                                        ? m.Groups[2].ToString()
                                        : m.Groups[1] + replacement + m.Groups[3]
                                    );
            });
}

这与另一个答案类似,但它考虑使用 {{text}} 进行转义。

public static string StringFormat(this string format, IDictionary<string, object> values)
{
    return Regex.Matches(format, @"\{(?!\{)(.+?)\}")
            .Select(m => m.Groups[1].Value)
            .Aggregate(format, (current, key) =>
            {
                string[] splits = key.Split(":");
                string replacement = splits.Length > 1
                    ? string.Format(
quot;{{0:{splits[1]}}}", values[splits[0]])
                    : values[key].ToString();
                return Regex.Replace(current, "(.|^)("+ Regex.Escape(
quot;{{{key}}}")+")(.|$)", 
                                     m => m.Groups[1].ToString() == "{" && m.Groups[3].ToString() == "}"
                                        ? m.Groups[2].ToString()
                                        : m.Groups[1] + replacement + m.Groups[3]
                                    );
            });
}

This is similar to another answer, but it considers escaping with {{text}}.

≈。彩虹 2024-08-01 01:08:58

我采用了@LPCRoy的答案并针对通用字典类型进行了重构,添加了参数验证,它仅替换它可以找到的字段,并尝试通过首先转义它们来解决“双花括号”问题,然后在末尾用单大括号替换它们与 string.Format() 的方式相同。

public static string FormatFromDictionary<K, T>(this string formatString, IDictionary<K, T> valueDict)
{
    if (string.IsNullOrWhiteSpace(formatString)) return formatString;
    if (valueDict == null || !valueDict.Any()) return formatString;

    bool escapedDoubleCurlyBraces = false;
    if (formatString.Contains("{{") || formatString.Contains("}}"))
    {
        formatString = formatString.Replace("{{", "\\{\\{").Replace("}}", "\\}\\}");
        escapedDoubleCurlyBraces = true;
    }

    int i = 0;
    StringBuilder newFormatString = new StringBuilder(formatString);
    Dictionary<K, int> keyToInt = new Dictionary<K, int>();
    string field;

    //StringBuilder.Replace() is faster than string.Replace().
    foreach (var kvp in valueDict)
    {
        field = "{" + kvp.Key.ToString() + "}";
        if (formatString.Contains(field))
        {
            newFormatString = newFormatString.Replace(field, "{" + i.ToString() + "}");
            keyToInt.Add(kvp.Key, i);
            i++;
        }
    }

    //Any replacements to make?
    if (keyToInt.Any())
    {
        formatString = string.Format(
            newFormatString.ToString(),
            keyToInt.OrderBy(kvp => kvp.Value).Select(kvp => (object)valueDict[kvp.Key]).ToArray()
        );
    }
    if (escapedDoubleCurlyBraces)
    {
        //Converts "{{" and "}}" to single "{" and "}" for the final result just like string.format().
        formatString = formatString.Replace("\\{\\{", "{").Replace("\\}\\}", "}");
    }

    return formatString;
}

I took @LPCRoy's answer and refactored for generic dictionary types, added parameter validation, it only replaces fields it can find, and attempts to solve the "double curly brace" issue by escaping them first, then replacing them at the end with single braces in the same way that string.Format() does.

public static string FormatFromDictionary<K, T>(this string formatString, IDictionary<K, T> valueDict)
{
    if (string.IsNullOrWhiteSpace(formatString)) return formatString;
    if (valueDict == null || !valueDict.Any()) return formatString;

    bool escapedDoubleCurlyBraces = false;
    if (formatString.Contains("{{") || formatString.Contains("}}"))
    {
        formatString = formatString.Replace("{{", "\\{\\{").Replace("}}", "\\}\\}");
        escapedDoubleCurlyBraces = true;
    }

    int i = 0;
    StringBuilder newFormatString = new StringBuilder(formatString);
    Dictionary<K, int> keyToInt = new Dictionary<K, int>();
    string field;

    //StringBuilder.Replace() is faster than string.Replace().
    foreach (var kvp in valueDict)
    {
        field = "{" + kvp.Key.ToString() + "}";
        if (formatString.Contains(field))
        {
            newFormatString = newFormatString.Replace(field, "{" + i.ToString() + "}");
            keyToInt.Add(kvp.Key, i);
            i++;
        }
    }

    //Any replacements to make?
    if (keyToInt.Any())
    {
        formatString = string.Format(
            newFormatString.ToString(),
            keyToInt.OrderBy(kvp => kvp.Value).Select(kvp => (object)valueDict[kvp.Key]).ToArray()
        );
    }
    if (escapedDoubleCurlyBraces)
    {
        //Converts "{{" and "}}" to single "{" and "}" for the final result just like string.format().
        formatString = formatString.Replace("\\{\\{", "{").Replace("\\}\\}", "}");
    }

    return formatString;
}
冬天旳寂寞 2024-08-01 01:08:58

这是一个很好的解决方案,在格式化电子邮件时非常有用: http://www.c-sharpcorner.com/UploadFile/e4ff85/string-replacement-with-named-string-placeholders/

编辑:

public static class StringExtension  
{  
    public static string Format( this string str, params Expression<Func<string,object>>[] args)  
    {  
        var parameters = args.ToDictionary( e=>string.Format("{{{0}}}",e.Parameters[0].Name), e=>e.Compile()(e.Parameters[0].Name));  

        var sb = new StringBuilder(str);  
        foreach(var kv in parameters)  
        {  
            sb.Replace( kv.Key, kv.Value != null ? kv.Value.ToString() : "");  
        }  

        return sb.ToString();  
    }  
}

示例用法:

public string PopulateString(string emailBody)  
{  
  User person = _db.GetCurrentUser();  
  string firstName = person.FirstName;    //  Peter  
  string lastName = person.LastName;      //  Pan  
  return StringExtension.Format(emailBody.Format(  
    firstname => firstName,  
    lastname => lastName  
  ));   
} 

Here is a nice solution that is very useful when formatting emails: http://www.c-sharpcorner.com/UploadFile/e4ff85/string-replacement-with-named-string-placeholders/

Edited:

public static class StringExtension  
{  
    public static string Format( this string str, params Expression<Func<string,object>>[] args)  
    {  
        var parameters = args.ToDictionary( e=>string.Format("{{{0}}}",e.Parameters[0].Name), e=>e.Compile()(e.Parameters[0].Name));  

        var sb = new StringBuilder(str);  
        foreach(var kv in parameters)  
        {  
            sb.Replace( kv.Key, kv.Value != null ? kv.Value.ToString() : "");  
        }  

        return sb.ToString();  
    }  
}

Example usage:

public string PopulateString(string emailBody)  
{  
  User person = _db.GetCurrentUser();  
  string firstName = person.FirstName;    //  Peter  
  string lastName = person.LastName;      //  Pan  
  return StringExtension.Format(emailBody.Format(  
    firstname => firstName,  
    lastname => lastName  
  ));   
} 
嘿嘿嘿 2024-08-01 01:08:58

(你的 Dictionary + foreach + string.Replace)包裹在子例程或扩展方法中?

显然没有优化,但是......

(your Dictionary + foreach + string.Replace) wrapped in a sub-routine or extension method?

Obviously unoptimized, but...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文