如何为字符串格式提供自定义字符串占位符

发布于 2024-07-26 01:16:13 字数 404 浏览 2 评论 0原文

我有一个字符串,

string str ="Enter {0} patient name";

我正在使用 string.format 来格式化它。

String.Format(str, "Hello");

现在,如果我还想从某些配置中检索病人,那么我需要将 str 更改为类似的内容 “输入 {0} {1} 名称”。 因此它将用第二个值替换 {1}。 问题是我想要代替 {1} 一些其他格式,例如 {pat}。 但是当我尝试使用时,它会抛出错误。 我想要不同格式的原因是我需要像这样更改很多文件(可能包含 {0}、{1} 等)。 所以我需要一个可以在运行时替换的自定义占位符。

I have a string

string str ="Enter {0} patient name";

I am using string.format to format it.

String.Format(str, "Hello");

Now if i want patient also to be retrieved from some config then I need to change str to something like
"Enter {0} {1} name". So it will replace the {1} with second value. The problem is that I want instead of {1} some other format something like {pat}. But when I try to use, it throws an error. The reason I want a different format is that there are lot of files I need to change like this(which may contain {0},{1} etc). So I need a custom placeholder which can be replaced at run-time.

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

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

发布评论

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

评论(9

零時差 2024-08-02 01:16:14

您可能想查看 FormatWith 2.0,作者:James Newton-King。 它允许您使用属性名称作为格式化标记,如下所示:

var user = new User()
{
    Name = "Olle Wobbla",
    Age = 25
};

Console.WriteLine("Your name is {Name} and your age is {Age}".FormatWith(user));

您还可以将其与匿名类型一起使用。

更新:还有一个类似的解决方案,作者是Scott Hanselman 但它是作为 Object 而不是 String 上的一组扩展方法实现的

更新 2012:您可以获取 Calrius Consulting 的 NETFx String.FormatWith 扩展方法 NuGet.org 上的 NuGet 包

2014 年更新:还有 StringFormat.NETlittlebit 的 StringFormat

You might want to check out FormatWith 2.0 by James Newton-King. It allows you to use property names as formatting tokens such as this:

var user = new User()
{
    Name = "Olle Wobbla",
    Age = 25
};

Console.WriteLine("Your name is {Name} and your age is {Age}".FormatWith(user));

You can also use it with anonymous types.

UPDATE: There is also a similar solution by Scott Hanselman but it is implemented as a set of extension methods on Object instead of String.

UPDATE 2012: You can get Calrius Consulting's NETFx String.FormatWith Extension Method NuGet package on NuGet.org

UPDATE 2014: There is also StringFormat.NET and littlebit's StringFormat

故事灯 2024-08-02 01:16:14

带有 MatchEvaluatorRegex 似乎是一个不错的选择:

static readonly Regex re = new Regex(@"\{([^\}]+)\}", RegexOptions.Compiled);
static void Main()
{
    string input = "this {foo} is now {bar}.";
    StringDictionary fields = new StringDictionary();
    fields.Add("foo", "code");
    fields.Add("bar", "working");

    string output = re.Replace(input, delegate (Match match) {
        return fields[match.Groups[1].Value];
    });
    Console.WriteLine(output); // "this code is now working."
}

Regex with a MatchEvaluator seems a good option:

static readonly Regex re = new Regex(@"\{([^\}]+)\}", RegexOptions.Compiled);
static void Main()
{
    string input = "this {foo} is now {bar}.";
    StringDictionary fields = new StringDictionary();
    fields.Add("foo", "code");
    fields.Add("bar", "working");

    string output = re.Replace(input, delegate (Match match) {
        return fields[match.Groups[1].Value];
    });
    Console.WriteLine(output); // "this code is now working."
}
浅沫记忆 2024-08-02 01:16:14
object[] myInts = new int[] {8,9}; 

但是你可以逃避:

object[] myInts = new string[] { "8", "9" }; 
string bar = string.Format("{0} {1}", myInts); 
object[] myInts = new int[] {8,9}; 

However you can get away with:

object[] myInts = new string[] { "8", "9" }; 
string bar = string.Format("{0} {1}", myInts); 
提笔落墨 2024-08-02 01:16:14

您可能最好对自定义字段使用 Replace,对其余字段使用 Format,例如:

string str = "Enter {0} {pat} name";
String.Format(str.Replace("{pat}", "Patient"), "Hello");

You are probably better off using Replace for the custom field and Format for the rest, like:

string str = "Enter {0} {pat} name";
String.Format(str.Replace("{pat}", "Patient"), "Hello");
余生再见 2024-08-02 01:16:14

我看到了上面的所有答案,但无法正确回答问题:)

以下代码不满足您的要求是否有任何特殊原因?

string myFirstStr = GetMyFirstStrFromSomewhere();
string mySecondStr = GetMySecondStrFromSomewhere();

string result = "Enter " + myFirstStr + " " + mySecondStr + " name";

I saw all the answers above, yet, couldn't get the question right :)

Is there any particular reason why the following code does not meet your requirement?

string myFirstStr = GetMyFirstStrFromSomewhere();
string mySecondStr = GetMySecondStrFromSomewhere();

string result = "Enter " + myFirstStr + " " + mySecondStr + " name";
み青杉依旧 2024-08-02 01:16:14

这是我在这里找到的另一个版本: http://www.reddit .com/r/programming/comments/bodml/beef_up_params_in_c_5_to_solve_lambda_abuse/c0nrsf1

任何解决方案都将涉及反射,这不太理想,但这里是他的代码,解决了其他一些主要性能问题。 (没有错误检查。如果您愿意,可以添加它。):

1) 使用直接运行时反射,没有 DataBinder 开销

2) 不使用正则表达式,使用单遍解析和状态。

3) 不将字符串转换为中间字符串,然后再次将其转换为最终格式。

4) 使用单个 StringBuilder 进行分配和连接,而不是到处更新字符串并将它们连接成新字符串。

5) 消除了为 n 次替换操作调用委托的堆栈开销。

6) 一般来说,单次传递将以相对线性的方式扩展(每个 prop 查找和嵌套 prop 查找仍然有一些成本,但仅此而已。)

public static string FormatWith(this string format, object source)
{
    StringBuilder sbResult = new StringBuilder(format.Length);
    StringBuilder sbCurrentTerm = new StringBuilder();
    char[] formatChars = format.ToCharArray();
    bool inTerm = false;
    object currentPropValue = source;

    for (int i = 0; i < format.Length; i++)
    {
        if (formatChars[i] == '{')
            inTerm = true;
        else if (formatChars[i] == '}')
        {
            PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString());
            sbResult.Append((string)(pi.PropertyType.GetMethod("ToString", new Type[]{}).Invoke(pi.GetValue(currentPropValue, null), null)));
            sbCurrentTerm.Clear();
            inTerm = false;
            currentPropValue = source;
        }
        else if (inTerm)
        {
            if (formatChars[i] == '.')
            {
                PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString());
                currentPropValue = pi.GetValue(source, null);
                sbCurrentTerm.Clear();
            }
            else
                sbCurrentTerm.Append(formatChars[i]);
        }
        else
            sbResult.Append(formatChars[i]);
    }
    return sbResult.ToString();
} 

Here's another version of this that I found here: http://www.reddit.com/r/programming/comments/bodml/beef_up_params_in_c_5_to_solve_lambda_abuse/c0nrsf1

Any solution to this is going to involve reflection, which is less than ideal, but here's his code with some of the other major performance issues resolved. (No error checking. Add it if you like.):

1) Uses direct runtime reflection, no DataBinder overhead

2) Doesn't use regular expressions, uses a single-pass parse and state.

3) Doesn't convert the string into an intermediate string and then convert it again to the final format.

4) Allocates and concatenates with a single StringBuilder instead of newing up strings all over the place and concatenating them into new strings.

5) Removes the stack overhead of calling a delegate for n replace operations.

6) In general is a single pass through that will scale in a relatively linear manner (still some cost for each prop lookup and nested prop lookup, but that's that.)

public static string FormatWith(this string format, object source)
{
    StringBuilder sbResult = new StringBuilder(format.Length);
    StringBuilder sbCurrentTerm = new StringBuilder();
    char[] formatChars = format.ToCharArray();
    bool inTerm = false;
    object currentPropValue = source;

    for (int i = 0; i < format.Length; i++)
    {
        if (formatChars[i] == '{')
            inTerm = true;
        else if (formatChars[i] == '}')
        {
            PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString());
            sbResult.Append((string)(pi.PropertyType.GetMethod("ToString", new Type[]{}).Invoke(pi.GetValue(currentPropValue, null), null)));
            sbCurrentTerm.Clear();
            inTerm = false;
            currentPropValue = source;
        }
        else if (inTerm)
        {
            if (formatChars[i] == '.')
            {
                PropertyInfo pi = currentPropValue.GetType().GetProperty(sbCurrentTerm.ToString());
                currentPropValue = pi.GetValue(source, null);
                sbCurrentTerm.Clear();
            }
            else
                sbCurrentTerm.Append(formatChars[i]);
        }
        else
            sbResult.Append(formatChars[i]);
    }
    return sbResult.ToString();
} 
固执像三岁 2024-08-02 01:16:14

您还可以使用 Marc Gravell 和扩展 String 类对象中的示例:

public static class StringExtension
{
    static readonly Regex re = new Regex(@"\{([^\}]+)\}", RegexOptions.Compiled);
    public static string FormatPlaceholder(this string str, Dictionary<string, string> fields)
    {
        if (fields == null)
            return str;

        return re.Replace(str, delegate(Match match)
        {
            return fields[match.Groups[1].Value];
        });

    }
}

示例用法:

String str = "I bought a {color} car";
Dictionary<string, string> fields = new Dictionary<string, string>();
fields.Add("color", "blue");

str.FormatPlaceholder(fields));

You can also use the example from Marc Gravell and Extend the String class object:

public static class StringExtension
{
    static readonly Regex re = new Regex(@"\{([^\}]+)\}", RegexOptions.Compiled);
    public static string FormatPlaceholder(this string str, Dictionary<string, string> fields)
    {
        if (fields == null)
            return str;

        return re.Replace(str, delegate(Match match)
        {
            return fields[match.Groups[1].Value];
        });

    }
}

Example usage:

String str = "I bought a {color} car";
Dictionary<string, string> fields = new Dictionary<string, string>();
fields.Add("color", "blue");

str.FormatPlaceholder(fields));
慕巷 2024-08-02 01:16:14
var user = new User()
{
    Name = "John",
    Age = 21
};
String result = 
quot;Your name is {user.Name} and your age is {user.Age}";
var user = new User()
{
    Name = "John",
    Age = 21
};
String result = 
quot;Your name is {user.Name} and your age is {user.Age}";
小草泠泠 2024-08-02 01:16:14

我想要一些更像 Python 字符串格式化的东西,所以我写了这个:
https://gist.github.com/samwyse/b225b32ae1aea6fb27ad9c966b9ca90b

像这样使用它:

Dim template = New FormatFromDictionary("{cat} vs {dog}")
Dim d = New Dictionary(Of String, Object) From {
    {"cat", "Felix"}, {"dog", "Rex"}}
Console.WriteLine(template.Replace(d)) ' Felix vs Rex

I wanted something that worked more like Python's string formatting, so I wrote this:
https://gist.github.com/samwyse/b225b32ae1aea6fb27ad9c966b9ca90b

Use it like this:

Dim template = New FormatFromDictionary("{cat} vs {dog}")
Dim d = New Dictionary(Of String, Object) From {
    {"cat", "Felix"}, {"dog", "Rex"}}
Console.WriteLine(template.Replace(d)) ' Felix vs Rex
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文