Recursive Replace
От: Ilinichev  
Дата: 17.06.13 08:38
Оценка:
Есть такой XML-файл:

<ReplaceSubstrings>
  <ReplaceSubstring Name="f4" Value="{f0}\{f1}\{f2}\abcd" />
  <ReplaceSubstring Name="f0" Value="abcd" />
  <ReplaceSubstring Name="f1" Value="{f0}\abcd" />
  <ReplaceSubstring Name="f2" Value="{f0}\{f1}\abcd" />
  <ReplaceSubstring Name="f3" Value="{f0}\{f2}\abcd" />
</ReplaceSubstrings>


Десериализуется в массив таких экземпляров:

public class ReplaceSubstring
{
    public string Name { get; set; }
    public string Value { get; set; }
}


Как правильно написать алгоритм, чтобы получить Dictionary<string,string> или массив тех же ReplaceSubstring, где значения взаимно уже раскрыты и кольцевые ссылки обработаны (поднятием исключения)?
Re: Recursive Replace
От: matumba  
Дата: 17.06.13 09:30
Оценка:
Здравствуйте, Ilinichev, Вы писали:

I>Есть такой XML-файл:


I>Как правильно написать алгоритм


Если "правильно", то только головой!
Мы услышали саму задачу. В чём состоит ВАША ПРОБЛЕМА, что вы даже не пытаетесь её решить?
Re[2]: Recursive Replace
От: Ilinichev  
Дата: 17.06.13 09:39
Оценка:
Здравствуйте, matumba, Вы писали:

I>>Есть такой XML-файл:

I>>Как правильно написать алгоритм
M>Если "правильно", то только головой!
M>Мы услышали саму задачу. В чём состоит ВАША ПРОБЛЕМА, что вы даже не пытаетесь её решить?

Пытаюсь, но не уверен, что правильно. Изначальная проблема в том, что в конфигурационном XML-файле надо задать много строк, в частности, в качестве значений атрибутов, в которых (в этих строках) часто повторяются подстроки. Например так:

<MyCfgFile>
  <MyCfgSection>
    <MyCfgTag Attr1="" Attr2="" Attr3="" />
    <MyCfgTag Attr1="" Attr2="" Attr3="" />
    <!-- ...много... -->
    <MyCfgTag Attr1="" Attr2="" Attr3="" />
    <MyCfgTag Attr1="" Attr2="" Attr3="" />
  </MyCfgSection>
</MyCfgFile>


Вот в этих Attr1, Attr2, Attr3 и т.п. значения — строки, пути к ресурсам. Пути к ресурсам часто повторяются, и могут иметь вообще разный смысл, семантически неопределенный, по типу строки-моникера в COM.

Решил сделать в этом конфигурационном файле такую секцию, как в ТС, а повтоворяющиеся подстроки в Attr1, Attr2, Attr3 и т.п. заменить на ключи этих подстрок. Вот, собственно, и все.
Re: Recursive Replace
От: Sinix  
Дата: 17.06.13 10:04
Оценка: 3 (1)
Здравствуйте, Ilinichev, Вы писали:

I>Как правильно написать алгоритм, чтобы получить Dictionary<string,string> или массив тех же ReplaceSubstring, где значения взаимно уже раскрыты и кольцевые ссылки обработаны (поднятием исключения)?


Я бы позаимствовал общую логику у environment variables — порядок определения важен, каждая строка обрабатывается сразу при прочтении.
Тогда ваша проблема сводится к последовательной обработке каждой строки и написанию ReplaceMany.

P.S. Dictionary отпадает сразу — он не гарантирует порядок хранения элементов.
Re[3]: Recursive Replace
От: matumba  
Дата: 17.06.13 10:14
Оценка:
Здравствуйте, Ilinichev, Вы писали:

I><MyCfgFile>

I> <MyCfgSection>
I> <MyCfgTag Attr1="" Attr2="" Attr3="" />

I>Вот в этих Attr1, Attr2, Attr3 и т.п. значения — строки, пути к ресурсам. Пути к ресурсам часто повторяются


Хех, так вы пытаетесь уменьшить размер конфига — это главная задача?
Re[4]: Recursive Replace
От: Ilinichev  
Дата: 17.06.13 10:22
Оценка:
Здравствуйте, matumba, Вы писали:

I>>Вот в этих Attr1, Attr2, Attr3 и т.п. значения — строки, пути к ресурсам. Пути к ресурсам часто повторяются


M>Хех, так вы пытаетесь уменьшить размер конфига — это главная задача?


Нет, главная задача не размер, а читабельность.
Re: Многопроходное разрешение (раскрытие) ссылок
От: igor-booch Россия  
Дата: 17.06.13 12:01
Оценка: 2 (1)
1. Создаем Dictionary<Name, Value>, у которого в Value не раскрытые ссылки на ReplaceSubstring
2. Делаем все возможные раскрытия
Для каждого Value, каждую ссылку на ReplaceSubstring заменяем на соответствующее ReplaceSubstring.Value (после замены, идем к следующей ссылке на ReplaceSubstring (вглубь не идем))
3. Остались не раскрытые значения? Возвращаемся к шагу 2.
ReplaceSubstring.Value ссылается само на себя -> эксепшен — кольцевая ссылка.

Такой подход не требует жесткого порядка следования ReplaceSubstring'ов
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Re[2]: Недостаток
От: igor-booch Россия  
Дата: 17.06.13 12:08
Оценка:
Сложность алгоритма будет похуже, чем у Sinix
Автор: Sinix
Дата: 17.06.13
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Re[2]: Многопроходное разрешение (раскрытие) ссылок
От: Ilinichev  
Дата: 17.06.13 12:27
Оценка: +1
Здравствуйте, igor-booch, Вы писали:

IB>1. Создаем Dictionary<Name, Value>, у которого в Value не раскрытые ссылки на ReplaceSubstring

IB>2. Делаем все возможные раскрытия
IB>Для каждого Value, каждую ссылку на ReplaceSubstring заменяем на соответствующее ReplaceSubstring.Value (после замены, идем к следующей ссылке на ReplaceSubstring (вглубь не идем))
IB>3. Остались не раскрытые значения? Возвращаемся к шагу 2.

Интересно, а как можно узнать, остались не раскрытые значения или нет? Я использовал условие "если не произошло ни одного раскрытия в п.2, прекращаем цикл while(true)".

IB>ReplaceSubstring.Value ссылается само на себя -> эксепшен — кольцевая ссылка.

IB>Такой подход не требует жесткого порядка следования ReplaceSubstring'ов

Я вот сам не понял, почему мне уперлось, не требовать жесткого порядка, т.к. на самом деле это ничего не дает — кольцевые ссылки так или иначе невозможно обойти, а вот увидеть их глазами в конфигурации сложнее. На самом деле, теперь я увидел, что требовать жесткого порядка гораздо читабельнее получается, т.к. отлаживать человеку гораздо легче, если что пойдет не так.
Re[3]: Многопроходное разрешение (раскрытие) ссылок
От: igor-booch Россия  
Дата: 17.06.13 13:13
Оценка:
I>Интересно, а как можно узнать, остались не раскрытые значения или нет? Я использовал условие "если не произошло ни одного раскрытия в п.2, прекращаем цикл while(true)".
Можно и так.

IB>>Такой подход не требует жесткого порядка следования ReplaceSubstring'ов

I>Я вот сам не понял, почему мне уперлось, не требовать жесткого порядка, т.к. на самом деле это ничего не дает — кольцевые ссылки так или иначе невозможно обойти, а вот увидеть их глазами в конфигурации сложнее. На самом деле, теперь я увидел, что требовать жесткого порядка гораздо читабельнее получается, т.к. отлаживать человеку гораздо легче, если что пойдет не так.
Да, будет читабельней. Хотя если Вам потребуется разбить ReplaceSubstring'и по смысловым группам и наиболее важные смысловые группы поместить в начало порядок может быть нарушен.
Добавление ReplaceSubstring и изменение ReplaceSubstring.Value будет дороже и сложнее, если требуется строгий порядок. Хотя я предполагаю, что чтение у Вас будет намного чаще, чем запись и вряд ли производительность записи в конфиг критична. Дороговизна записи зависит от среднего количества ссылок на один ReplaceSubstring.
Еще это может пригодиться, если у Вас уже есть большие конфиги с неупорядоченными ReplaceSubstring'ами. Хотя можно можно написать прогу, которая их упорядочит, но это дополнительный геморрой при деплое.
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Re: Recursive Replace
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.06.13 09:36
Оценка: 7 (2)
Здравствуйте, Ilinichev, Вы писали:

I>
I>public class ReplaceSubstring
I>{
I>    public string Name { get; set; }
I>    public string Value { get; set; }
I>}
I>


Dictionary<string, Lazy<ReplaceString>> repls;
repls = parsed.ToDictionary(repl => repl.Name, repl => new Lazy<ReplaceSubstring>(() => Subst(repl, repls)));


Реализацию Subst и отслеживание циклических ссылок оставляю тебе.
... << RSDN@Home 1.2.0 alpha 5 rev. 99 on Windows 8 6.2.9200.0>>
AVK Blog
Re[2]: Recursive Replace
От: Ilinichev  
Дата: 18.06.13 10:17
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Dictionary<string, Lazy<ReplaceString>> repls;
AVK>repls = parsed.ToDictionary(repl => repl.Name, repl => new Lazy<ReplaceSubstring>(() => Subst(repl, repls)));

AVK>Реализацию Subst и отслеживание циклических ссылок оставляю тебе.

Не приходилось еще использовать этот Lazy'T. Идея интересная, но у меня такое ощущение, что оно уйдет в бесконечный цикл даже если не будет никаких циклических ссылок в подстроках. Сейчас попробую.
Re[2]: Recursive Replace
От: Ilinichev  
Дата: 18.06.13 10:48
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Dictionary<string, Lazy<ReplaceString>> repls;
AVK>repls = parsed.ToDictionary(repl => repl.Name, repl => new Lazy<ReplaceSubstring>(() => Subst(repl, repls)));

AVK>Реализацию Subst и отслеживание циклических ссылок оставляю тебе.

Нет, не понимаю, не вижу смысла. Смысл есть только в одном случае, когда формат заменяемых подстрок известен, например, {key}, тогда при первом доступе к значению можно увидеть, что надо найти значения и вставить их в placeholder-ы, а значения раскручивать дальше. Но в моём случае формат заменяемых подстрок неизвестен, поэтому, если я правильно конечно же всё понял, Lazy<T> не дает никаких преимуществ, только запутывает всё. Или я не прав?
Re[3]: Recursive Replace
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.06.13 11:19
Оценка:
Здравствуйте, Ilinichev, Вы писали:

I>Не приходилось еще использовать этот Lazy'T. Идея интересная, но у меня такое ощущение, что оно уйдет в бесконечный цикл даже если не будет никаких циклических ссылок в подстроках.


Если не будет — не уйдет. А вот циклические ссылки надо отслеживать.
... << RSDN@Home 1.2.0 alpha 5 rev. 99 on Windows 8 6.2.9200.0>>
AVK Blog
Re[3]: Recursive Replace
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.06.13 11:19
Оценка:
Здравствуйте, Ilinichev, Вы писали:

I>Нет, не понимаю, не вижу смысла.


Что не понимаешь?

I> Смысл есть только в одном случае, когда формат заменяемых подстрок известен, например, {key}, тогда при первом доступе к значению можно увидеть, что надо найти значения и вставить их в placeholder-ы, а значения раскручивать дальше. Но в моём случае формат заменяемых подстрок неизвестен


Тут уже я нифига не понял из этой фразы.

I>, поэтому, если я правильно конечно же всё понял, Lazy<T> не дает никаких преимуществ, только запутывает всё. Или я не прав?


Вопрос не понятен. Какие преимущества ты ищешь у Lazy<T> и зачем? Lazy<T> просто позволяет ресолвить по требованию. В реальности лучше кешик, но в фреймворке готовых классов таких нет, поэтому для простоты в примере использован Lazy.
... << RSDN@Home 1.2.0 alpha 5 rev. 99 on Windows 8 6.2.9200.0>>
AVK Blog
Re[4]: Recursive Replace
От: Ilinichev  
Дата: 19.06.13 06:29
Оценка:
Здравствуйте, AndrewVK, Вы писали:

I>> Смысл есть только в одном случае, когда формат заменяемых подстрок известен, например, {key}, тогда при первом доступе к значению можно увидеть, что надо найти значения и вставить их в placeholder-ы, а значения раскручивать дальше. Но в моём случае формат заменяемых подстрок неизвестен

AVK>Тут уже я нифига не понял из этой фразы.
AVK>Lazy<T> просто позволяет ресолвить по требованию.

Спасибо, разобрался. Я имел в виду, что как только ты захочешь разресолвить случайно выбранный элемент из множества первый раз, придется в общем случае автоматом ресолвить все остальные элементы. Вот если ввести формат заменяемых подстрок, например, ключи — они в фигурных скобках — {key} или в символах процента — %key%, тогда бы при ресолве любого элемента можно было бы построить дерево и ресолвить не все множество элементов, а только те, ключи которых указаны в исходном значении запрошенного элемента. Да, в таком случае получается преимущество. И, каюсь, прошу прощения, только сейчас обратил внимание на то, что в примере ТС написал как раз так, как-будто формат заменяемых подстрок оговорен, а сам все время исходил из того, что он не определен, т.е вот из этого:

<ReplaceSubstrings>
  <ReplaceSubstring Name="{f4}" Value="-=f0=-\_f1\!f2\abcd" />
  <ReplaceSubstring Name="-=f0=-" Value="abcd" />
  <ReplaceSubstring Name="_f1}" Value="-=f0=-\abcd" />
  <ReplaceSubstring Name="!f2" Value="-=f0=-\_f1\abcd" />
  <ReplaceSubstring Name="*f3*" Value="-=f0=-\!f2\abcd" />
  <ReplaceSubstring Name="abcd" Value="xyz" />
</ReplaceSubstrings>



В общем, как-то не осознавал я важность этого момента. Только вчера, отвечая тебе, сообразил, что над форматом подстрок даже не думал.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.