Dimka
							
								Деятель 
								Команда клуба
								
								 
								  Offline
								Пол:   
								
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 «  : 09-12-2009 17:01 »   | 
								
								 | 
							  
							 
							Может кто-нибудь знает штатное средство в .NET, умеющее печатать строчку по формату, заданному в стиле C-шного printf?
  Т.е. на входе имеется строка типа "f%04ds", как с её помощью в .NET получить серию строк вида "f0000s", "f0001s" и т.д.
  Как-то не радует перспектива писать свой конвертор C-style форматных строк в .NET-style форматные вида "f{0:0000}s". 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел) 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Malaja
							
						 | 
						
							
								  | 
								
									
									 « Ответ #1 : 09-12-2009 17:14 »   | 
								
								 | 
							  
							 
							Дим, ты имеешь в виду вот это: strStr = String.Format("int = {0:D} *** float = {1:f} *** {2:S} *** {3:0}", 5, 5.5, "lala", 0.000);
 на выходе: "int = 5 *** float = 5,50 *** lala *** 0" или я не так поняла? Тогда извини...  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							холоднокровней, Маня, Ви не на работе --------------------------------------- четкое определение сущности бытия: - А мы в прошлом или в будущем?- спросила Алиса. - Мы в жопе, - ответил кролик. - А "жопа" - это настоящее? - спросила Алиса. - А "жопа" - это у нас символ вечности. 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Алексей++
							
								глобальный и пушистый 
								Глобальный модератор
								
								 
								  Offline
								
								Сообщений: 13
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									 « Ответ #2 : 09-12-2009 17:47 »   | 
								
								 | 
							  
							 
							А вставка блока кода на с++ возможна ? 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Malaja
							
						 | 
						
							
								  | 
								
									
									 « Ответ #3 : 09-12-2009 18:00 »   | 
								
								 | 
							  
							 
							Леш, куда ты хочешь его вставлять?      
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							холоднокровней, Маня, Ви не на работе --------------------------------------- четкое определение сущности бытия: - А мы в прошлом или в будущем?- спросила Алиса. - Мы в жопе, - ответил кролик. - А "жопа" - это настоящее? - спросила Алиса. - А "жопа" - это у нас символ вечности. 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Алексей++
							
								глобальный и пушистый 
								Глобальный модератор
								
								 
								  Offline
								
								Сообщений: 13
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									 « Ответ #4 : 09-12-2009 18:07 »   | 
								
								 | 
							  
							 
							Может я что-то путаю, Ну вроде дот-нет позиционировался как кроссплатформенный и кроссязыковый ? И можно делать вставки на любом языке, так же, как в с++ можно делать вставки ассемблера 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 10-12-2009 03:51 от Алексей1153++ »
								 | 
								
									 
									Записан
								 | 
							  
							 
							
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Malaja
							
						 | 
						
							
								  | 
								
									
									«  Ответ #5 : 09-12-2009 21:48 »    | 
								
								 | 
							  
							 
							Леш, не знаю, ничего не могу сказать... 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							холоднокровней, Маня, Ви не на работе --------------------------------------- четкое определение сущности бытия: - А мы в прошлом или в будущем?- спросила Алиса. - Мы в жопе, - ответил кролик. - А "жопа" - это настоящее? - спросила Алиса. - А "жопа" - это у нас символ вечности. 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Dimka
							
								Деятель 
								Команда клуба
								
								 
								  Offline
								Пол:   
								
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #6 : 10-12-2009 08:59 »   | 
								
								 | 
							  
							 
							Malaja, я имею в виду вот это как конечный результат преобразования, а на входе форматная строка с синтаксисом printf.
  В общем, свой конвертор написал. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел) 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Malaja
							
						 | 
						
							
								  | 
								
									
									 « Ответ #7 : 10-12-2009 10:52 »   | 
								
								 | 
							  
							 
							понятно. тогда прости за ненужную инфу. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							холоднокровней, Маня, Ви не на работе --------------------------------------- четкое определение сущности бытия: - А мы в прошлом или в будущем?- спросила Алиса. - Мы в жопе, - ответил кролик. - А "жопа" - это настоящее? - спросила Алиса. - А "жопа" - это у нас символ вечности. 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Sla
							
						 | 
						
							
								  | 
								
									
									 « Ответ #8 : 10-12-2009 10:59 »   | 
								
								 | 
							  
							 
							ой, нескромно так   Код в студию    
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Мы все учились понемногу... Чему-нибудь и как-нибудь. 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Dimka
							
								Деятель 
								Команда клуба
								
								 
								  Offline
								Пол:   
								
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #9 : 10-12-2009 15:25 »   | 
								
								 | 
							  
							 
							На выходных. Он у меня сейчас не универсальный, а заточенный только под целые числа и под один аргумент. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел) 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Dimka
							
								Деятель 
								Команда клуба
								
								 
								  Offline
								Пол:   
								
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #10 : 12-12-2009 13:08 »   | 
								
								 | 
							  
							 
							Собственно, вот.     class C     {         private class CFormat         {             [Flags]             private enum FormatFlags             {                 None = 0,                 LeftAlign = 1,                 PlusSign = 2,                 FirstZeros = 4,                 Blank = 8,                 LastZeros = 16             }
              private struct NumberParameter             {                 public bool Exist;                 public int? Value;             }
              private delegate object NextArg(Type expectedType);
              private string result;             private Stack args;
              public CFormat(string format, params object[] args)             {                 this.args = new Stack();                 for (int i = args.Length - 1; i >= 0; --i)                 {                     this.args.Push(args[i]);                 }                 Regex regex = new Regex(@"%(?<flag>[-+0 #]*)(?<width>\*|\d+)?(?<precision>\.\d*)?(?<size>[hlIw]|ll|I32|I64)?(?<type>[cCdiouxXeEfgGnpsS])");                 this.result = regex.Replace(format, new MatchEvaluator(this.replace)).Replace("%%", "%");             }
              public string Result             {                 get                 {                     return this.result;                 }             }
              private object getNextArg(Type expectedType)             {                 if (this.args.Count == 0)                 {                     throw new ArgumentOutOfRangeException();                 }                 object arg = this.args.Pop();                 if (arg.GetType() != expectedType)                 {                     throw new InvalidCastException();                 }                 return arg;             }
              private string replace(Match match)             {                 FormatFlags flags = this.parseFlags(match.Groups["flag"].Value);                 NumberParameter width = this.parseWidth(match.Groups["width"].Value, this.getNextArg);                 NumberParameter precision = this.parsePrecision(match.Groups["precision"].Value);                 string type = match.Groups["type"].Value;                 object value = this.getNextArg(this.detectValueType(type, match.Groups["size"].Value));                 string result = string.Empty;                 switch (type)                 {                     case "i":                     case "d":                         Int64 intValue = Convert.ToInt64(value);                         result = string.Format("{0:D}", Math.Abs(intValue));                         string sign = string.Empty;                         if (intValue >= 0)                         {                             if ((flags & FormatFlags.PlusSign) != 0)                             {                                 sign = "+";                             }                             else if ((flags & FormatFlags.Blank) != 0)                             {                                 sign = " ";                             }                         }                         else                         {                             sign = "-";                         }                         int fieldSize = width.Value.HasValue ? width.Value.Value - (sign + result).Length : 0;                         StringBuilder fieldBuilder = new StringBuilder();                         char fieldChar =                              (flags & FormatFlags.FirstZeros) != 0 && !precision.Exist && (flags & FormatFlags.LeftAlign) == 0                                 ? '0' : ' ';                         for(int i = 0; i < fieldSize; ++i)                         {                                 fieldBuilder.Append(fieldChar);                         }                         string field = fieldBuilder.ToString();                         if (field.Length > 0 && field[0] == '0')                         {                             result = sign + field + result;                         }                         else if ((flags & FormatFlags.LeftAlign) != 0)                         {                             result = sign + result + field;                         }                         else                         {                             result = field + sign + result;                         }                         break;                     default:                         throw new InvalidDataException();                 }                 return result;             }
              private Type detectValueType(string type, string size)             {                 switch (type)                 {                     case "i":                     case "d":                         switch (size)                         {                             case "h":                                 return typeof(short);                             case "l":                                 return typeof(long);                             case "ll":                             case "I64":                                 return typeof(Int64);                             case "I32":                                 return typeof(Int32);                             default:                                 return typeof(int);                         }                     default:                         return null;                 }             }
              private FormatFlags parseFlags(string flags)             {                 FormatFlags result = FormatFlags.None;                  foreach (char c in flags)                 {                     switch (c)                     {                         case '-':                             result |= FormatFlags.LeftAlign;                             break;                         case '+':                             result |= FormatFlags.PlusSign;                             break;                         case ' ':                             result |= FormatFlags.Blank;                             break;                         case '0':                             result |= FormatFlags.FirstZeros;                             break;                         case '#':                             result |= FormatFlags.LastZeros;                             break;                     }                 }                 return result;             }
              private NumberParameter parseNumberParameter(string numberParameter)             {                 NumberParameter result = new NumberParameter();                 result.Exist = numberParameter != string.Empty;                 if(result.Exist)                 {                     result.Value = Convert.ToInt32(numberParameter);                 }                 else                 {                     result.Value = null;                 }                 return result;             }
              private NumberParameter parseWidth(string width, NextArg getNextArg)             {                 if (width == "*")                 {                     NumberParameter result = new NumberParameter();                     result.Exist = true;                     result.Value = Convert.ToInt32(getNextArg(typeof(int)));                     return result;                 }                 else                 {                     return this.parseNumberParameter(width);                 }             }
              private NumberParameter parsePrecision(string precision)             {                 bool isPoint = precision.Length > 0 && precision[0] == '.';                 if (isPoint)                 {                     NumberParameter result = this.parseNumberParameter(precision.Substring(1));                     result.Exist = true;                     return result;                 }                 else                 {                     return this.parseNumberParameter(precision);                 }             }         }
          public static string sprintf(string format, params object[] args)         {             return new CFormat(format, args).Result;         }
          public static void printf(string format, params object[] args)         {             Console.Write(C.sprintf(format, args));         }
          public static void fprintf(Stream openedFile, string format, params object[] args)         {             new StreamWriter(openedFile).Write(C.sprintf(format, args));         }     } Сделал универсальный и расширяемый анализатор, но из всех возможных значений типов терпения хватило только на целые числа. Остальное мне сейчас не надо, а нуждающиеся допишут сами. Использование типа: C.printf("'%-8ld', '%+08i' '%*d'\n", (long)12, -32, 8, 24); Вывод: Кто баги найдёт - пишите. Ведёт оно себя строже, чем в C, в части контроля типов. P.S. Добавил звёздочку (см. ниже).  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 13-12-2009 08:36 от Dimka »
								 | 
								
									 
									Записан
								 | 
							  
							 
							Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел) 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Алексей++
							
								глобальный и пушистый 
								Глобальный модератор
								
								 
								  Offline
								
								Сообщений: 13
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									 « Ответ #11 : 12-12-2009 13:36 »   | 
								
								 | 
							  
							 
							Ещё есть звёздочка, я вот так сразу не нашёл, где обрабатывается. Например  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Dimka
							
								Деятель 
								Команда клуба
								
								 
								  Offline
								Пол:   
								
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #12 : 12-12-2009 14:45 »   | 
								
								 | 
							  
							 
							Алексей1153++, да, звёздочки в этой реализации нет. Нужно расширить регулярное выражение и кое-что перекомпоновать.
  Пока добавлял звёздочку, баг нашёл из-за порчи дизайна - говорили же умные люди, что нефиг в функции побочные эффекты закладывать. Хорошо бы перепроектировать. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 12-12-2009 15:08 от Dimka »
								 | 
								
									 
									Записан
								 | 
							  
							 
							Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел) 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Алексей++
							
								глобальный и пушистый 
								Глобальный модератор
								
								 
								  Offline
								
								Сообщений: 13
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									 « Ответ #13 : 13-12-2009 05:46 »   | 
								
								 | 
							  
							 
							А что за побочные эффекты ? Кстати, "x","X" (большой X - для заглавных хексов) - тоже целые     
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 13-12-2009 05:48 от Алексей1153++ »
								 | 
								
									 
									Записан
								 | 
							  
							 
							
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Dimka
							
								Деятель 
								Команда клуба
								
								 
								  Offline
								Пол:   
								
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #14 : 13-12-2009 07:40 »   | 
								
								 | 
							  
							 
							Алексей1153++, нет, u, o и x - это уже желающие пусть сами дописывают. Побочные эффекты в том, что функция вычисления ширины теперь тоже берёт аргумент, и, в частности, поэтому получение значения должно быть обязательно после вызова функции вычисления ширины, и два раза повторяется проверка на выход за пределы массива. Некрасиво это. Чуть переделал, вынеся логику контроля типов и выхода за пределы в отедльную функцию - генератор аргументов. Но всё равно сохраняется неочевидность внутри replace, что получение значения должно следовать обязательно после вычисления ширины. Несовершенный код. Нужно, чтобы аргументы извлекались в одном месте, но извлечение аргумента при вычислении ширины возможно лишь в результате анализа. Размазывать логику вычисления ширины по двум функциям тоже нехорошо. Сливать всё в одну функцию replace - это получить перегруженный деталями код. У кого какие предложения будут? Решение выглядело бы изящнее, если бы вместо регулярных выражений, предоставляющих неупорядоченное множество групп, был бы написан собственный автомат разбора, с явной последовательностью состояний, но это было бы более громоздко. Так и хочется написать что-то вроде анонимного метода или блока кода, передаваемого как аргумент функции. Добавил делегат в параметры функции вычисления ширины, чтобы синтаксически указать в replace зависимость функции вычисления ширины от стека аргументов. Всё равно не изящно.    
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 13-12-2009 08:41 от Dimka »
								 | 
								
									 
									Записан
								 | 
							  
							 
							Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел) 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Алексей++
							
								глобальный и пушистый 
								Глобальный модератор
								
								 
								  Offline
								
								Сообщений: 13
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									 « Ответ #15 : 13-12-2009 09:00 »   | 
								
								 | 
							  
							 
							Глянул, как делается в CString - там тоже для определения длины буфера назначения код парсинга прогоняется два раза.
  А может быть, сделать мини-кеш, буквально на одну строчку - если входная строка такая же, как предыдущая, то на выход уходит сразу готовая (также предыдущая) выходная строка ? 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Dimka
							
								Деятель 
								Команда клуба
								
								 
								  Offline
								Пол:   
								
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #16 : 13-12-2009 09:51 »   | 
								
								 | 
							  
							 
							По-моему с длиной строк в .NET проблем нет. Единственно, что складывание строк в циклах не является оптимальными - лучше использовать StringBuilder.
  По поводу кэша была идея: сформировать сначала форматную строчку в стиле .NET, а потом к ней применять аргументы. Но контроль типов идёт лесом, а, с другой стороны, такое решение лучше делать по схеме Regex (т.е. формат задать в конструкторе, а потом печатать с его помощью аргументы), нежели статическим методом - усложняется использование. Поэтому такой вариант выгоден лишь для более узкой задачи - печати разных данных по одному формату. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 13-12-2009 09:52 от Dimka »
								 | 
								
									 
									Записан
								 | 
							  
							 
							Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел) 
						 | 
					 
				 
			 |  
		 
	 | 
	 |