Заменить все вхождения со свойствами объекта


Основная идея заключается в том, чтобы заменить все специальные выражения, например, [%InvoiceNo%], [%для duedate%], в строке свойств объекта, счета-фактуры.

string str = "Your invoice [%InvoiceNo%] will be due on [%DueDate%]";
Invoice invoice = new Invoice { InvoiceNo = "123456", DueDate = DateTime.Parse("2011.12.29") };
string result = GetNewValue(str, invoice);
//The expected result is: Your invoice 123456 will be due on 11/29/2011

Я думаю, что самый простой способ реализации GetNewValue() может быть

private string GetNewValue(string str, Invoice invoice)
{
    str = str.Replace("[%InvoiceNo%]", invoice.InvoiceNo);
    str = str.Replace("[%DueDate%]", invoice.DueDate.ToString());
    return str;
}

Однако, в моем случае, счет-фактура сто свойства и целевая строка содержит только один или два свойства. Я переписывать GetNewValue() так, как я думаю, она должна работать более эффективно. Вот мой код

private string GetNewValue(string str, Invoice invoice)
{
    List<string> expressions = new List<string>();
    List<string> fields = new List<string>();

    var startIndices = str.IndicesOf("[%");
    var endIndices = str.IndicesOf("%]");
    int startLen = "[%".Length;
    int endLen = "%]".Length;

    for (int i = 0; i < startIndices.Count; i++)
    {
        expressions.Add(str.Substring(startIndices[i], 
                                      endIndices[i] - startIndices[i] + endLen));
        fields.Add(str.Substring(startIndices[i] + startLen, 
                                 endIndices[i] - startIndices[i] - startLen));
    }

    for (int i = 0; i < expressions.Count; i++)
        str = str.Replace(expressions[i], invoice.GetValueByName(fields[i]).ToString());

    return str;
}

StringExtender IndicesOf()

public static List<int> IndicesOf(this string target, string search)
{
    List<int> indices = new List<int>();
    int startIndex = 0;
    int index;

    while ((index = target.IndexOf(search, startIndex)) > -1)
    {
        indices.Add(index);
        startIndex = index + 1;
    }

    return indices;
}

GetValueByName() с помощью отражения

public class Invoice
{
    // Properties
    ......

    public object GetValueByName(string name)
    {
        PropertyInfo myProperty = typeof(Invoice).GetProperty(name);
        return myProperty.GetValue(this, null);
    }
}

Как я могу улучшить этот код? Быстро, меньше памяти, или один-лайнер
Не говори мне, что первый подход лучше. ОРЗ
Спасибо :)



5913
1
задан 30 ноября 2011 в 03:11 Источник Поделиться
Комментарии
2 ответа

Вы можете сделать это в одну петлю вместо того, чтобы получить все индексы отдельно. Просто с верхней части моей головы:

        string str = "Your invoice [%InvoiceNo%] will be due on [%DueDate%]";

int startIndex = 0;

while ((startIndex = str.IndexOf("[%", startIndex)) > -1)
{
int endIndex = str.IndexOf("%]", startIndex);
string exp = str.Substring(startIndex, endIndex - startIndex + 2);
string field = str.Substring(startIndex + 2, endIndex - startIndex - 2);
str = str.Replace(exp, invoice.GetValueByName(field).ToString());
startIndex = 0;
}

Некоторые замечания здесь:


  1. Я предполагаю, что вы гарантированно увидите %] если вы найдете [%

  2. Я не тест на крайние случаи, как то, что если стр = "[%счет%]"

Это изящное решение, но чем больше я думаю о вашей проблеме, тем больше я задаюсь вопросом, если вы можете не инженер, так что вы пройти, какие поля вы хотите свой счет объект, и он просто возвращает строку, так что вам не нужно возиться с заполнителями... пища для размышлений :)

2
ответ дан 30 ноября 2011 в 05:11 Источник Поделиться

ул. Заменить много копирования за кадром. Особенно если у вас сложный строку, вы бы лучше с помощью класса StringBuilder в петлю. Что-то вроде (непроверенных код):

StringBuilder sb = new StringBuilder();
int idx = 0;
while (true) {
int nextIdx = str.IndexOf("[%", idx);
if (nextIdx < 0) break;
// Copy unexpanded text
sb.Append(str, idx, nextIdx - idx);
// Find end
int endIdx = str.IndexOf("%]", nextIdx);
if (endIdx < 0) throw new Exception("Unmatched [%");
// Copy the substitution and then skip past it
string field = str.Substring(nextIdx + 2, endIdx - nextIdx + 2);
sb.Append(GetValueByName(invoice, field));
idx = nextIdx + 2;
}
// Copy the tail.
sb.Append(str, idx, str.Length - idx);
return sb.ToString();

НБ я предположил, что GetValueByName теперь статическое поле - это не имеет никакого смысла для меня, чтобы это было Способ счета, как что и толкает функциональность на счет, который не имеет ничего общего с выставлением счета, и ограничивает его применимость. Я был бы соблазн сделать это метод расширения объекта.

Кроме того, я использовал свой [% для консистенции, но когда я делаю подобные вещи я предпочитаю использовать { и повторно использовать строку.Форматс синтаксисом. Я также ручки :formattingString и объекта iformatprovider в качестве аргумента.

1
ответ дан 30 ноября 2011 в 11:11 Источник Поделиться