Считать числовые данные из текстового SPICE файла и записать их в свои переменные - C#
Формулировка задачи:
Доброго времени суток!...возникла такая проблемка: имеется текстовый файл формата SPICE (пример ниже):
.model 2T3107E PNP (Is=991.3f Xti=3 Eg=1.11 Vaf=35 Bf=210 Ne=1.58
+ Ise=8.12p Ikf=80m Xtb=1.5 Br=2.86 Nc=2 Isc=100p Ikr=80m Rc=7
+ Cjc=7.37p Vjc=.7 Mjc=.333 Fc=.5 Cje=10.6p Vje=.75 Mje=.3333
+ Tr=80p Tf=113p Itf=8m Vtf=50 Xtf=1.2)
Нужно прочитать из такого файла ЧИСЛОВЫЕ значения параметров элемента (в данном случае описание модели транзистора) и записать каждый параметр в свою переменную, например: значение Is=991.3f в переменную, допустим, double IS, Xti=3 в переменную double Xti и т. д.
Особенности задачи определяются особеннностями синтаксиса языка SPICE, а именно:
а) параметры, которые необходимо записать в переменную заключены в круглые скобки; они (скобки) -
ОБЯЗАТЕЛЬНЫЙ элемент синтаксиса модели;
б) между наименованием параметра, знаком "равно" (знак "равно" является обязательным элементом синтаксиса) и числовым значением пробелов может не быть, может быть один или несколько, например: Is=991.3f или Is =991.3f или
Is= 991.3f или Is = 991.3f и т. д.;
в) распознать и определить множитель по буквенному индексу, например Ise=8.12p (пико-) это 8,12 умноженное на 10^-9 (т. е. занести в переменную double Ise = 8,12 / 10^9); Ikr=80m это 80 мили-, т .е. в переменную занести double Ikr=80 / 10^3 и т. д.;
г) между собой параметры ВСЕГДА разделены НЕ менее чем одним пробелом (больше одного возможно);
д) целая и дробная части числа могут разделяются как точкой, так и запятой, например: может быть так Br=2.86 или так Br=2,86 - при записи в переменную точки заменить на запятые;
е) при отсутствии у числа целой части - нуль в начале записи может присутствовать, а может и нет, например: может быть так Mjc=.333 или вот так Mjc=0.333 - при записи в перемнную автоматически подставлять "недостающий" нуль;
ж) последовательность перечисления параметров внутри круглых скобок - произвольная;
Дополнительные пояснения:
а) знак "плюс" - перенос строки (при чтении параметров игнорируется);
б) описание модели ВСЕГДА начинается с выражения ".model", а заканчивается закрывающей скобкой;
в) круглых скобок (с параметрами) всегда один "комплект".
Хотелость бы посмотреть похожий пример, причем не обязательно для SPICE, это может просто поиск в текстовом файле каких-нибудь именованных величин с их последующем занесем в переменные или, возможно, кто-то сможет показать (на примере одного-двух параметров) как реализовать поставленные задачи.
Заранее благодарен.
Решение задачи: «Считать числовые данные из текстового SPICE файла и записать их в свои переменные»
textual
Листинг программы
using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text; namespace ConsoleApplication2 { class Program { private static string Data = @".model 2T3107E PNP (Is=991.3f Xti= 3 Eg =1.11 Vaf = 35 +Bf=210 Ne=1.58 + Ise=8.12p Ikf=80m Xtb=1.5 Br=2.86 Nc=2 Isc=100p Ikr=80m Rc=7 + Cjc=7.37p Vjc=.7 Mjc=.333 Fc=.5 Cje=10.6p Vje=.75 Mje=.3333 + Tr=80p Tf=113p Itf=8m Vtf=50 Xtf=1.2) .model Q2N2222A NPN (IS=14.34F XTI=3 EG=1.11 VAF= 74.03 BF=255.9 NE=1.307 ISE=14.34F IKF=.2847 XTB=1.5 BR=6.092 NC=2 ISC=0 IKR=0 RC=1 CJC=7.306P MJC=.3416 VJC=.75 FC=.5 CJE=22.01P MJE=.377 VJE=.75 TR=46.91N TF=411.1P ITF=.6 VTF=1.7 XTF=3 RB=10)"; private static void Main(string[] args) { var ms = new StreamWriter(new MemoryStream()); ms.Write(Data); ms.Flush(); ms.BaseStream.Position = 0L; var sp = new SpiceParser(ms.BaseStream); } } public class SpiceModelParam { public SpiceModelParam() { } public SpiceModelParam(string name, float value = 0f) { Name = name; Value = value; } public string Name { get; set; } public float Value { get; set; } public override string ToString() { return string.Format("{0} = {1}", Name, Value); } } public class SpiceModel { public SpiceModel() { Parameters = new List<SpiceModelParam>(); } public SpiceModel(string name) : this() { Name = name; } public string Name { get; set; } public List<SpiceModelParam> Parameters { get; private set; } public override string ToString() { return string.Format("{0} [{1}]", Name, Parameters.Count); } } public class SpiceParser { private const string ModelID = ".model"; private StreamReader mReader; public SpiceParser(Stream stream) { if (!stream.CanRead || !stream.CanSeek) throw new Exception(); mReader = new StreamReader(stream); Models = new List<SpiceModel>(); Parse(); } public List<SpiceModel> Models { get; private set; } private void Parse() { while (!mReader.EndOfStream) { var line = ReadFullModel(); Models.Add(ParseModel(line)); } } private string ReadFullModel() { var sb = new StringBuilder(); while (true) { var line = mReader.ReadLine(); sb.Append(line); if (line.EndsWith(")")) break; } return sb.ToString(); } unsafe private void FixLine(char* ptr, int len) { var end = ptr + len; while (ptr != end) { if (*ptr == '+' || *ptr == '\n' || *ptr == '\r') *ptr = ' '; ptr++; } } unsafe private SpiceModel ParseModel(string line) { int offset = 0; if (!line.StartsWith(ModelID)) return null; offset += ModelID.Length + 1; var model = new SpiceModel(); fixed (char* ptr = line) { FixLine(ptr, line.Length); char* pName = ptr + offset; pName = ParseModelName(pName, model); if (*pName == '(') ParseParams(++pName, model); } return model; } unsafe private char* ParseModelName(char* pName, SpiceModel model) { int i = 0; for (; pName[i] != '('; ++i) ; model.Name = new string(pName, 0, i - 1); return pName + i; } unsafe private void ParseParams(char* ptr, SpiceModel model) { while (true) { var p = new SpiceModelParam(); ptr = ParseParamName(ptr, p); ptr = ParseParamEqual(ptr); ptr = ParseParamValue(ptr, p); model.Parameters.Add(p); if (*ptr == ')') return; else ptr++; } } private const float P = -1 * 10f * 10f * 10f * 10f * 10f * 10f * 10f * 10f * 10f; private const float M = -1f * 10f * 10f * 10f; private readonly char DecimalSeparator = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator[0]; unsafe private float ParseParamFactor(char* ptr) { switch (*ptr) { case 'p': case 'P': return P; case 'm': case 'M': return M; default: return 1f; } } unsafe private char* ParseParamValue(char* ptr, SpiceModelParam p) { int i = 0; while (*ptr == ' ') ptr++; while (true) { // Если . или , то заменяем её на символ // который применяется в текущей локализации if (ptr[i] == '.' || ptr[i] == ',') { ptr[i] = DecimalSeparator; } // Если текущий символ не цифра, то завершаемся else if (!(ptr[i] >= '0' && ptr[i] <= '9')) break; i++; } var str = new string(ptr, 0, i); p.Value = float.Parse(str); ptr += i; if (*ptr != ' ') p.Value *= ParseParamFactor(ptr); return ptr; } unsafe private char* ParseParamEqual(char* ptr) { // Пропускаем пробелы while (*ptr == ' ') ptr++; if (*ptr != '=') // Проверка корректности позиции throw new Exception(); return ++ptr; } unsafe private char* ParseParamName(char* ptr, SpiceModelParam p) { int i = 0; // Пропускаем пробелы while (*ptr == ' ') ptr++; // Имя параметра, до пробела или = while (ptr[i] != ' ' && ptr[i] != '=') i++; p.Name = new string(ptr, 0, i); // Перемещаемся за название параметра return ptr + i; } } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д