/
AstroJohn
/
MailRobot
Обзор
Документация
Войти
/
AstroJohn
/
MailRobot
Код
Запросы
0
Задачи
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
Parser/LogParser/mdlEDIParser.vb
1 202 строки
64 KB
AstroJohn
1st commit
11 сен 2024, 13:31
11 сен 2024, 13:31
0f57dc5
Код
Авторство
О чём код?
Imports System.Text Imports CsHelpers.SimpleHelpers Namespace LogParser #Region "Класс парсинга EDI" ''' <summary> ''' Класс EDI-парсинга ''' </summary> ''' <remarks></remarks> <Obsolete("Use Csharp!")> Public Class clsEDIParser Implements IParser Public Property LogStream As IO.Stream Implements IParser.LogStream 'ввод потока с отчетом Public Property ParsedLog As clsParsedLog Implements IParser.ParsedLog 'вывод результатов парсинга Public Property FileName As String Implements IParser.FileName Public Property ParsedLogs As List(Of clsParsedLog) Private HeaderFields As New Collection Private QSOCount As Integer Private Parameters As clsParserParameters #Region "Константы" Private Const MAXIMUM_TOTAL_ERRORS_WARNINGS As Integer = 15 Private Const HEADER_DELIMITER As Char = "="c Private Const START_OF_LOG As String = "\[REG1TEST;.*\]" Private Const START_OF_QSOS As String = "\[QSORecords;\d+\]" Private Const START_OF_REMARKS As String = "\[Remarks;?.*\]" Private Const END_OF_LOG As String = "\[END;.*\]" Private Const END_OF_LOG_2 As String = "\[END\]" ''' <summary> ''' Разделы EDI-отчета ''' </summary> ''' <remarks></remarks> Private Enum EDI_LOG_PARTS None = 0 Headers = 1 Remarks = 2 QSOs = 3 End_of_log = 4 End Enum #End Region #Region "Массивы допустимых значений" ''' <summary> ''' Массив значений PBand ''' </summary> ''' <remarks></remarks> Private PBAND_VALUES() As String = { "50 MHz", "70 MHz", "144 MHz", "432 MHz", "1,3 GHz", "2,3 GHz", "3,4 GHz", "5,7 GHz", "10 GHz", "24 GHz", "47 GHz", "76 GHz", "120 GHz", "144 GHz", "248 GHz" } #End Region #Region "Конструктор" Public Sub New(Parameters As clsParserParameters) Me.Parameters = Parameters End Sub #End Region #Region "Функции и методы" ''' <summary> ''' Парсинг значений строки заголовка ''' </summary> ''' <param name="Header"></param> ''' <returns></returns> ''' <remarks></remarks> Private Function ParseHeaderValues(Header As clsParsedHeader) As clsParseResult Dim ParseResult As New clsParseResult ParseResult.Type = PARSE_ERROR_TYPE.NONE ParseResult.Message = String.Empty Select Case Header.Name Case "TName" If Parameters.ContestName <> Header.Value Then ParseResult.Type = PARSE_ERROR_TYPE.WARNING ParseResult.Message = "Warning: Check that you have sent a log not for another contest." + Environment.NewLine + Space(4) + "Contest must be " + Me.Parameters.ContestName + "." ParseResult.Message_Rus = "Предупреждение: проверьте, что вы не отослали отчет за другой контест." + Environment.NewLine + Space(4) + "Строка с ключевым словом CONTEST должна содержать значение " + Parameters.ContestName + "." End If Case "MOpe1", "MOpe2", "MOpe3", "MOpe4", "MOpe5", "MOpe6" If (Left(ParsedLog.Callsign, 1) = "R" _ Or (Left(ParsedLog.Callsign, 2) >= "UA" And Left(ParsedLog.Callsign, 2) <= "UI") _ Or ParsedLog.Callsign = "OH5HM") _ And Parameters.ContestName <> "VHF-ACTIVITY" Then If Header.Value <> String.Empty Then Dim OPs As String() Dim flag As Boolean OPs = Header.Value.Replace(";", "~").Replace(",", "~").Replace(" ", "~").Replace("~~", "~").Split("~"c) flag = OPs.Length = 6 If flag Then 'год рождения flag = IsNumeric(OPs(5)) End If If Not flag Then ParseResult.Type = PARSE_ERROR_TYPE.BAD ParseResult.Message = "Error: Line with tag " + Header.Name + " is invalid. See comment in russian above." ParseResult.Message_Rus = Environment.NewLine + Space(4) + "Ошибка: Строки с ключевыми словами MOpe1, MOpe2 и т. п. должны содержать" + Environment.NewLine + Space(4) + "данные в следующем порядке: личный позывной, фамилия, имя, отчество," + Environment.NewLine + Space(4) + "спортивный разряд/звание, год рождения." + Environment.NewLine + Space(4) + "Пример:" + Environment.NewLine + Space(4) + "MOpe1=UA8AAA;Иванов Иван Иванович;КМС;1966" End If End If End If Case "TDate" Case "PCall" Case "PWWLo" Case "PExch" Case "PAdr1" Case "PAdr2" Case "PSect" Case "PBand" Dim Band As String = Header.Value.Trim Band = Band.Replace("145", "144") Band = Band.Replace("435", "432") Band = Band.Replace("430", "432") Band = Band.Replace("433", "432") Band = Band.Replace(".", ",") Band = Band.Replace("1,2", "1,3") Band = Band.Replace("1296 MHz", "1,3 GHz") If Band.Contains("MHz") _ And Not Band.Contains(" MHz") Then Band = Band.Replace("MHz", " MHz") End If If Band.Contains("GHz") _ And Not Band.Contains(" GHz") Then Band = Band.Replace("GHz", " GHz") End If If Array.IndexOf(PBAND_VALUES, Band) < 0 Then ParseResult.Type = PARSE_ERROR_TYPE.BAD Else Dim RX As New Text.RegularExpressions.Regex("\s*") Band = RX.Replace(Band, "") Band = Band.Replace("MHz", "").Replace("GHz", "G") ParsedLog.Band = Band End If Case "PClub" Case "RName" If (Left(ParsedLog.Callsign, 1) = "R" _ Or (Left(ParsedLog.Callsign, 2) >= "UA" And Left(ParsedLog.Callsign, 2) <= "UI")) _ And Me.Parameters.ContestName <> "VHF-ACTIVITY" Then Dim flag As Boolean = False If Header.Value <> String.Empty Then Dim OPs As String() OPs = Header.Value.Replace(";", "~").Replace(",", "~").Replace(" ", "~").Replace("~~", "~").Split("~"c) flag = OPs.Length = 5 If flag Then 'год рождения flag = IsNumeric(OPs(4)) End If End If If Not flag Then ParseResult.Type = PARSE_ERROR_TYPE.BAD ParseResult.Message = "Error: Line with tag " + Header.Name + " is invalid. See comment in russian above." ParseResult.Message_Rus = Environment.NewLine + Strings.Space(4) + "Ошибка: Строка с ключевыми словами <RName> должна содержать" + Environment.NewLine + Strings.Space(4) + "данные в следующем порядке: фамилия, имя, отчество," + Environment.NewLine + Strings.Space(4) + "спортивный разряд/звание, год рождения." + Environment.NewLine + Strings.Space(4) + "Пример:" + Environment.NewLine + Strings.Space(4) + "RName=Иванов Иван Иванович;КМС;1966" End If End If Case "RCall" Case "RAdr1" Case "RAdr2" Case "RPoCo" Case "RCity" Case "RCoun" Case "RPhon" Case "RHBBS" Case "STXEq" Case "SPowe" Case "SRXEq" Case "SAnte" Case "SAntH" Case "CQSOs" Case "CQSOP" Case "CWWLs" Case "CWWLB" Case "CExcs" Case "CExcB" Case "CDXCs" Case "CDXCB" Case "CToSc" Case "CODXC" Case Else ParseResult.Type = PARSE_ERROR_TYPE.WARNING ParseResult.Message = "Warning: Tag " + Header.Name + " is not known for the system." ParseResult.Message_Rus = "Предупреждение: Ключевое слово " + Header.Name + " неизвестно системе." End Select If ParseResult.Type = PARSE_ERROR_TYPE.BAD Then If ParseResult.Message = String.Empty Then If Header.Name = "PBand" Then ParseResult.Message = "Error: Invalid band " + Header.Value + ". Look at line with ""PBand"" tag." ParseResult.Message_Rus = "Ошибка: Неверный диапазон " + Header.Value + ". Обратите внимание на строку отчета с ключевым словом ""PBand""." Else ParseResult.Message = "Error: Line with tag " + Header.Name + " contains invalid value " + Header.Value + "." ParseResult.Message_Rus = "Ошибка: Строка с ключевым словом " + Header.Name + " содержит неверное значение " + Header.Value + "." End If End If End If Return ParseResult End Function ''' <summary> ''' Парсинг строки заголовка ''' </summary> ''' <param name="HeaderString"></param> ''' <returns></returns> ''' <remarks></remarks> Private Function ParseHeaderString(HeaderString As String) As clsParsedHeader Dim ParsedHeader As New clsParsedHeader Dim DoubleDotPosition As Integer With ParsedHeader DoubleDotPosition = InStr(HeaderString, HEADER_DELIMITER) If DoubleDotPosition = 0 Then .ParseResult.Type = PARSE_ERROR_TYPE.BAD .ParseResult.Message = "Tag not found." .ParseResult.Message_Rus = "Ключевое слово не найдено." Else .ParseResult.Type = PARSE_ERROR_TYPE.NONE .Name = Left(HeaderString, DoubleDotPosition - 1) If DoubleDotPosition = HeaderString.Length Then .Value = String.Empty Else .Value = Trim(Replace(Right(HeaderString, HeaderString.Length - DoubleDotPosition), Chr(9), " ", , , CompareMethod.Text)) End If End If End With Return ParsedHeader End Function ''' <summary> ''' Парсинг строки раздела EDI-отчета вида [Header;Value] ''' </summary> ''' <param name="DivisionString"></param> ''' <returns></returns> ''' <remarks></remarks> Private Function ParseDivisionString(DivisionString As String) As clsParsedHeader Dim ParsedHeader As New clsParsedHeader Dim DelimiterPosition As Integer With ParsedHeader DelimiterPosition = InStr(DivisionString, ";"c) If DelimiterPosition = 0 Then .Value = String.Empty Else .ParseResult.Type = PARSE_ERROR_TYPE.NONE .Name = Mid(DivisionString, 2, DelimiterPosition - 2) .Value = Mid(DivisionString, DelimiterPosition + 1, DivisionString.Length - DelimiterPosition - 1) End If End With Return ParsedHeader End Function ''' <summary> ''' Парсинг строки QSO новым методом (сплит, важен порядок данных, точное расположение не имеет значения) ''' </summary> ''' <param name="QSOString"></param> ''' <returns></returns> ''' <remarks></remarks> Private Function ParseQSOString(QSOString As String, CallSign As String) As clsParsedQSO Dim ParsedQSO As New clsParsedQSO Dim TempSt As String Dim DataColumns() As String = { "date", "time", "station callsign", "mode", "sent RS(T)", "sent number", "received RS(T)", "received number", "received additional exchange", "received QTH locator", "QSO points", "new exchange flag", "new QTH locator flag", "new DXCC flag", "duplicate QSO flag" } Dim DataColumns_Rus() As String = { "дата", "время", "принятый позывной", "вид работы", "переданный рапорт", "переданный порядковый номер", "принятый рапорт", "принятый порядковый номер", "принятый дополнительный номер", "принятый QTH локатор", "очки за QSO", "флаг нового дополнительного номера", "флаг нового QTH локатора", "флаг новой страны по DXCC", "флаг повторной связи" } Try With ParsedQSO Dim QSOParams As String() = QSOString.Split(";"c) Dim Columns_number As Integer = QSOParams.Length If Columns_number < 10 Then .ParseResult.Type = PARSE_ERROR_TYPE.BAD .ParseResult.Message += "Invalid QSO line format." .ParseResult.Message_Rus += "Неверный формат строки QSO." Return ParsedQSO End If TempSt = QSOParams(3) Dim Mode As String = String.Empty If IsValidMode(TempSt, Mode) Then .Mode = Mode Else If Len(QSOParams(4)) = 2 Then If CallSign = "ES6FX" Then Mode = "FM" Else Mode = "SSB" End If ElseIf Len(QSOParams(4)) = 3 Then Mode = "CW" End If If .ParseResult.Type = PARSE_ERROR_TYPE.NONE Then .ParseResult.Type = PARSE_ERROR_TYPE.WARNING End If .ParseResult.Message += Environment.NewLine + " " + "Mode is incorrect or not specified. It will be assumed " + Mode + ". " .ParseResult.Message_Rus += Environment.NewLine + " " + "Вид работы неверный или не указан. Будет предполагаться " + Mode + ". " .Mode = Mode End If TempSt = QSOParams(0) If Not CheckDateFormat(TempSt, .Time) Then .ParseResult.Type = PARSE_ERROR_TYPE.BAD .ParseResult.Message += Environment.NewLine + " " + "Invalid date: " + TempSt + ". " .ParseResult.Message_Rus += Environment.NewLine + " " + "Неверная дата: " + TempSt + ". " End If TempSt = QSOParams(1) If Not CheckTimeFormat(TempSt, .Time) Then .ParseResult.Type = PARSE_ERROR_TYPE.BAD .ParseResult.Message += Environment.NewLine + " " + "Invalid time: " + TempSt + ". " .ParseResult.Message_Rus += Environment.NewLine + " " + "Неверное время: " + TempSt + ". " End If TempSt = QSOParams(4) If Not IsValidReport(TempSt) Then If .ParseResult.Type = PARSE_ERROR_TYPE.NONE Then .ParseResult.Type = PARSE_ERROR_TYPE.WARNING End If If TempSt = String.Empty Then .ParseResult.Message += Environment.NewLine + " " + "Empty sent RST. " .ParseResult.Message_Rus += Environment.NewLine + " " + "Не указан переданный рапорт. " Else .ParseResult.Message += Environment.NewLine + " " + "Invalid sent RST: " + TempSt + ". " .ParseResult.Message_Rus += Environment.NewLine + " " + "Неверный переданный рапорт: " + TempSt + ". " End If Else If Me.Parameters.ContestName <> "SPB-OPEN-VHF" Then .SentNr = TempSt Else .SentNr = "" End If If Me.Parameters.ContestName = "VHF-ACTIVITY" Then .SentNr = .SentNr + Space(1) + ParsedLog.Location End If End If If Me.Parameters.ContestName <> "VHF-ACTIVITY" Then TempSt = QSOParams(5).Replace("o", "0").Replace("O", "0") If TempSt = String.Empty _ OrElse Not IsNumeric(TempSt) Then If .ParseResult.Type = PARSE_ERROR_TYPE.NONE Then .ParseResult.Type = PARSE_ERROR_TYPE.WARNING End If If TempSt = String.Empty Then .ParseResult.Message += Environment.NewLine + " " + "Empty sent exchange. " .ParseResult.Message_Rus += Environment.NewLine + " " + "Не указан переданный контрольный номер. " Else .ParseResult.Message += Environment.NewLine + " " + "Invalid sent exchange: " + TempSt + ". " .ParseResult.Message_Rus += Environment.NewLine + " " + "Неверный переданный контрольный номер: " + TempSt + ". " End If Else .SentNr = .SentNr + " " + FormatSerialNr(TempSt) + " " + ParsedLog.Location End If End If TempSt = QSOParams(2).Trim If TempSt = String.Empty _ OrElse Not IsValidCallsign(TempSt) Then If .ParseResult.Type = PARSE_ERROR_TYPE.NONE Then .ParseResult.Type = PARSE_ERROR_TYPE.WARNING End If .ParseResult.Message += Environment.NewLine + " " + "Invalid station callsign: " + TempSt + ". " .ParseResult.Message_Rus += Environment.NewLine + " " + "Неверный позывной корреспондента: " + TempSt + ". " Else .Stn = TempSt End If TempSt = QSOParams(6) If Not IsValidReport(TempSt) Then If .ParseResult.Type = PARSE_ERROR_TYPE.NONE Then .ParseResult.Type = PARSE_ERROR_TYPE.WARNING End If If TempSt = String.Empty Then .ParseResult.Message += Environment.NewLine + " " + "Empty received RST. " .ParseResult.Message_Rus += Environment.NewLine + " " + "Не указан принятый рапорт. " Else .ParseResult.Message += Environment.NewLine + " " + "Invalid received RST: " + TempSt + ". " .ParseResult.Message_Rus += Environment.NewLine + " " + "Неверный принятый рапорт: " + TempSt + ". " End If Else If Me.Parameters.ContestName <> "SPB-OPEN-VHF" Then .RcvdNr = TempSt Else .RcvdNr = "" End If End If If Me.Parameters.ContestName <> "VHF-ACTIVITY" Then TempSt = QSOParams(7) If TempSt = String.Empty _ OrElse Not IsNumeric(TempSt) Then If .ParseResult.Type = PARSE_ERROR_TYPE.NONE Then .ParseResult.Type = PARSE_ERROR_TYPE.WARNING End If If TempSt = String.Empty Then .ParseResult.Message += Environment.NewLine + " " + "Empty received exchange. " .ParseResult.Message_Rus += Environment.NewLine + " " + "Не указан принятый контрольный номер. " Else .ParseResult.Message += Environment.NewLine + " " + "Invalid received exchange: " + TempSt + ". " .ParseResult.Message_Rus += Environment.NewLine + " " + "Неверный принятый контрольный номер: " + TempSt + ". " End If Else .RcvdNr = .RcvdNr + " " + FormatSerialNr(TempSt) End If End If TempSt = QSOParams(9).ToUpper If Not IsValidLocator(TempSt) Then If .ParseResult.Type = PARSE_ERROR_TYPE.NONE Then .ParseResult.Type = PARSE_ERROR_TYPE.WARNING End If If TempSt = String.Empty Then .ParseResult.Message += Environment.NewLine + " " + "Empty received QTH locator. " .ParseResult.Message_Rus += Environment.NewLine + " " + "Не указан принятый QTH локатор. " Else .ParseResult.Message += Environment.NewLine + " " + "Invalid received QTH locator: " + TempSt + ". " .ParseResult.Message_Rus += Environment.NewLine + " " + "Неверный принятый QTH локатор: " + TempSt + ". " End If Else .RcvdNr = .RcvdNr + " " + TempSt End If Me.CheckQSO_ContestSensitive(ParsedQSO) If .ParseResult.Message <> String.Empty _ And .ParseResult.Type <> PARSE_ERROR_TYPE.WARNING Then .ParseResult.Type = PARSE_ERROR_TYPE.BAD .ParseResult.Message = "Error: " + Left(.ParseResult.Message, .ParseResult.Message.Length - 1) .ParseResult.Message_Rus = "Ошибка: " + Left(.ParseResult.Message_Rus, .ParseResult.Message_Rus.Length - 1) End If .Band = ParsedLog.Band .CallSign = ParsedLog.Callsign End With Catch ex As Exception With ParsedQSO .ParseResult.Type = PARSE_ERROR_TYPE.BAD .ParseResult.Message += " System error: " + Replace(ex.Message, Environment.NewLine, "") .ParseResult.Message_Rus += " Системная ошибка: " + Replace(ex.Message, Environment.NewLine, "") End With End Try Return ParsedQSO End Function ''' <summary> ''' Парсинг отчета из потока байтов ''' </summary> ''' <remarks></remarks> Public Sub ParseLOG() Implements IParser.ParseLog Dim encoding As Encoding = Nothing Dim CurrentLogPart As EDI_LOG_PARTS = EDI_LOG_PARTS.None Dim TotalQSOCount As Integer = 0 ParsedLog = New clsParsedLog ParsedLogs = new List(Of clsParsedLog) ParsedLogs.Add(ParsedLog) QSOCount = 0 ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.NONE ParsedLog.ParseResult.Message = String.Empty ParsedLog.ParseResult.Message_Rus = String.Empty If LogStream Is Nothing _ OrElse LogStream.Length = 0 Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND Else Dim EndOfLog_Found As Boolean = False LogStream.Position = 0 encoding = FileEncoding.DetectFileEncoding(LogStream, Encoding.GetEncoding(1251)) if (Not encoding Is Nothing AndAlso encoding.CodePage = 1252) encoding = Encoding.GetEncoding(1251) End If HeaderFields = New Collection LogStream.Position = 0 Dim LOGLine As String Dim Reader As New IO.StreamReader(LogStream, encoding) Dim i As Integer = 0 Dim j As Integer = 0 Dim QSO_Parsing_errors As Integer = 0 Dim QSO_Parsing_warnings As Integer = 0 Do i += 1 LOGLine = Reader.ReadLine ParsedLog.Lines.Add(LOGLine) if (Left(LogLine, 10) = "==========") CurrentLogPart = EDI_LOG_PARTS.None TotalQSOCount = 0 ParsedLog = New clsParsedLog ParsedLogs.Add(ParsedLog) QSOCount = 0 ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.NONE ParsedLog.ParseResult.Message = String.Empty ParsedLog.ParseResult.Message_Rus = String.Empty j = 0 Continue Do Else If Not LOGLine Is Nothing _ AndAlso LOGLine.Trim <> String.Empty Then j += 1 Dim RX_START_OF_LOG As New Text.RegularExpressions.Regex(START_OF_LOG) Dim RX_START_OF_QSOS As New Text.RegularExpressions.Regex(START_OF_QSOS) Dim RX_START_OF_REMARKS As New Text.RegularExpressions.Regex(START_OF_REMARKS) Dim RX_END_OF_LOG As New Text.RegularExpressions.Regex(END_OF_LOG) Dim RX_END_OF_LOG_2 As New Text.RegularExpressions.Regex(END_OF_LOG_2) If CurrentLogPart = EDI_LOG_PARTS.None Then If RX_START_OF_LOG.Matches(LOGLine).Count = 1 Then CurrentLogPart = EDI_LOG_PARTS.Headers ElseIf j > 5 Then ' Начало отчета ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.FORMATTED_LOG_NOT_FOUND ParsedLog.ParseResult.Message = "Error: First line of a log must be [REG1TEST;1]." ParsedLog.ParseResult.Message_Rus = "Ошибка: Первая строка отчета должна быть [REG1TEST;1]." Exit Do End If ElseIf RX_START_OF_REMARKS.Matches(LOGLine).Count = 1 Then CurrentLogPart = EDI_LOG_PARTS.Remarks ElseIf RX_START_OF_QSOS.Matches(LOGLine).Count = 1 Then CurrentLogPart = EDI_LOG_PARTS.QSOs Dim ParsedHeader As clsParsedHeader = ParseDivisionString(LOGLine) If ParsedHeader.ParseResult.Type = PARSE_ERROR_TYPE.NONE Then If IsNumeric(ParsedHeader.Value) Then TotalQSOCount = CInt(ParsedHeader.Value) End If End If ElseIf RX_END_OF_LOG.Matches(LOGLine).Count = 1 _ Or RX_END_OF_LOG_2.Matches(LOGLine).Count = 1 Then CurrentLogPart = EDI_LOG_PARTS.End_of_log ' Конец отчета Dim ParsedHeader As clsParsedHeader = ParseDivisionString(LOGLine) If ParsedHeader.ParseResult.Type = PARSE_ERROR_TYPE.NONE Then ParsedHeader.Name = "Created-by" HeaderFields.Add(ParsedHeader) End If EndOfLog_Found = True Exit Do ElseIf CurrentLogPart = EDI_LOG_PARTS.Headers Then Dim ParsedHeader As clsParsedHeader = ParseHeaderString(LOGLine) If ParsedHeader.ParseResult.Type = PARSE_ERROR_TYPE.NONE Then HeaderFields.Add(ParsedHeader) Dim HeaderParseResult As clsParseResult = ParseHeaderValues(ParsedHeader) If HeaderParseResult.Type = PARSE_ERROR_TYPE.NONE Then If ParsedHeader.Name = "PCall" Then If ParsedLog.Callsign = String.Empty Then Dim Cl As String = Replace(Trim(ParsedHeader.Value), Strings.Chr(9), "") If IsValidCallsign(Cl) Then ParsedLog.Callsign = Cl Else ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND ParsedLog.ParseResult.Message += "Line " + i.ToString + ": " + "Invalid own callsign. Callsign must include only latin letters, digits and slash." + vbNewLine ParsedLog.ParseResult.Message_Rus += "Строка " + i.ToString + ": " + "Неверный свой позывной " + ParsedHeader.Value + ". Позывной может содержать лишь прописные латинские буквы, цифры и символы дроби." + vbNewLine 'EndOfLog_Found = True 'Exit Do End If Else ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND ParsedLog.ParseResult.Message += "Line " + i.ToString + ": " + "Several tags PCall found." + vbNewLine ParsedLog.ParseResult.Message_Rus += "Строка " + i.ToString + ": " + "Найдено несколько ключевых слов PCall." + vbNewLine 'EndOfLog_Found = True 'Exit Do End If ElseIf ParsedHeader.Name = "PWWLo" Then If ParsedHeader.Value.Length <> 6 Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND ParsedLog.ParseResult.Message += "Line " + i.ToString + ": " + "Wrong QTH Locator." + vbNewLine ParsedLog.ParseResult.Message_Rus += "Строка " + i.ToString + ": " + "Неверный QTH локатор." + vbNewLine ElseIf ParsedLog.Location = String.Empty Then ParsedLog.Location = ParsedHeader.Value.ToUpper Else ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND ParsedLog.ParseResult.Message += "Line " + i.ToString + ": " + "Several tags PWWLo found." + vbNewLine ParsedLog.ParseResult.Message_Rus += "Строка " + i.ToString + ": " + "Найдено несколько ключевых слов PWWLo." + vbNewLine 'EndOfLog_Found = True 'Exit Do End If ElseIf ParsedHeader.Name = "RHBBS" Then If ParsedLog.EMail = String.Empty Then ParsedLog.EMail = ParsedHeader.Value End If End If Else ParsedLog.ParseResult.Message += "Line " + i.ToString + ": " + HeaderParseResult.Message + vbNewLine ParsedLog.ParseResult.Message_Rus += "Строка " + i.ToString + ": " + HeaderParseResult.Message_Rus + vbNewLine End If If HeaderParseResult.Type = PARSE_ERROR_TYPE.CRITICAL Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND 'Exit Do End If If HeaderParseResult.Type = PARSE_ERROR_TYPE.OTHER_CONTEST Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.OTHER_CONTEST Exit Do End If If HeaderParseResult.Type = PARSE_ERROR_TYPE.BAD Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND End If If HeaderParseResult.Type = PARSE_ERROR_TYPE.WARNING Then If ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.NONE Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.WARNING End If End If If ParsedHeader.ParseResult.Type = PARSE_ERROR_TYPE.WARNING _ Or ParsedHeader.ParseResult.Type = PARSE_ERROR_TYPE.NONE Then ParsedLog.Headers.Add(ParsedHeader) End If End If ElseIf CurrentLogPart = EDI_LOG_PARTS.QSOs Then ' Строка QSO QSOCount = QSOCount + 1 Dim ParsedQSO As clsParsedQSO = ParseQSOString(LOGLine, ParsedLog.Callsign) If Not ParsedQSO Is Nothing Then If ParsedQSO.ParseResult.Type = PARSE_ERROR_TYPE.WARNING Then If QSO_Parsing_warnings <= MAXIMUM_TOTAL_ERRORS_WARNINGS Then ParsedLog.ParseResult.Message += "Line " + i.ToString + ": " + ParsedQSO.ParseResult.Message + vbNewLine ParsedLog.ParseResult.Message_Rus += "Строка " + i.ToString + ": " + ParsedQSO.ParseResult.Message_Rus + vbNewLine ElseIf QSO_Parsing_warnings = MAXIMUM_TOTAL_ERRORS_WARNINGS + 1 Then ParsedLog.ParseResult.Message += vbNewLine + "The number of QSOs with warnings exceeded " + MAXIMUM_TOTAL_ERRORS_WARNINGS.ToString + ". The output of warnings was breaked." + vbNewLine + vbNewLine ParsedLog.ParseResult.Message_Rus += vbNewLine + "Число радиосвязей с предупреждениями превысило " + MAXIMUM_TOTAL_ERRORS_WARNINGS.ToString + ". Вывод предупреждений прерван." + vbNewLine + vbNewLine End If ElseIf ParsedQSO.ParseResult.Type <> PARSE_ERROR_TYPE.NONE Then If QSO_Parsing_errors <= MAXIMUM_TOTAL_ERRORS_WARNINGS Then ParsedLog.ParseResult.Message += "Line " + i.ToString + ": " + ParsedQSO.ParseResult.Message + vbNewLine ParsedLog.ParseResult.Message_Rus += "Строка " + i.ToString + ": " + ParsedQSO.ParseResult.Message_Rus + vbNewLine ElseIf QSO_Parsing_errors = MAXIMUM_TOTAL_ERRORS_WARNINGS + 1 Then ParsedLog.ParseResult.Message += vbNewLine + "The number of QSOs with errors exceeded " + MAXIMUM_TOTAL_ERRORS_WARNINGS.ToString + ". The output of errors was breaked." + vbNewLine + vbNewLine ParsedLog.ParseResult.Message_Rus += vbNewLine + "Число радиосвязей с ошибками превысило " + MAXIMUM_TOTAL_ERRORS_WARNINGS.ToString + ". Вывод ошибок прерван." + vbNewLine + vbNewLine End If End If If (ParsedQSO.ParseResult.Type = PARSE_ERROR_TYPE.NONE Or ParsedQSO.ParseResult.Type = PARSE_ERROR_TYPE.WARNING) _ AndAlso ParsedLog.ContestDate Is Nothing Then ParsedLog.ContestDate = DateSerial(Year(ParsedQSO.Time), Month(ParsedQSO.Time), Day(ParsedQSO.Time)) End If If ParsedQSO.ParseResult.Type = PARSE_ERROR_TYPE.CRITICAL Then QSO_Parsing_errors += 1 ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND EndOfLog_Found = True Exit Do End If If ParsedQSO.ParseResult.Type = PARSE_ERROR_TYPE.BAD Then If QSOCount <= TotalQSOCount Then QSO_Parsing_errors += 1 ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND End If End If If ParsedQSO.ParseResult.Type = PARSE_ERROR_TYPE.WARNING Then QSO_Parsing_warnings += 1 If ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.NONE Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.WARNING End If End If If ParsedQSO.ParseResult.Type = PARSE_ERROR_TYPE.WARNING _ Or ParsedQSO.ParseResult.Type = PARSE_ERROR_TYPE.NONE Then ParsedLog.QSOs.Add(ParsedQSO) End If End If End If End If Loop Until LOGLine Is Nothing Reader.Close() If QSOCount = 0 Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND ParsedLog.ParseResult.Message = "Error: There are no QSOs in the log." + Environment.NewLine + ParsedLog.ParseResult.Message ParsedLog.ParseResult.Message_Rus = "Ошибка: В отчете нет ни одной связи." + Environment.NewLine + ParsedLog.ParseResult.Message_Rus End If If TotalQSOCount <> QSOCount Then If ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.NONE Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.WARNING End If ParsedLog.ParseResult.Message = "Warning: Number of QSOs is not corresponds to number from [QSORecords;] line." + Environment.NewLine + ParsedLog.ParseResult.Message ParsedLog.ParseResult.Message_Rus = "Предупреждение: Число связей не соответствует указанному в строке [QSORecords;]." + Environment.NewLine + ParsedLog.ParseResult.Message_Rus End If If Not EndOfLog_Found _ And ParsedLog.ParseResult.Type <> LOG_PARSE_ERROR_TYPE.FORMATTED_LOG_NOT_FOUND _ And ParsedLog.ParseResult.Type <> LOG_PARSE_ERROR_TYPE.OTHER_CONTEST _ And ParsedLog.ParseResult.Type <> LOG_PARSE_ERROR_TYPE.ERRORS_FOUND Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.WARNING ParsedLog.ParseResult.Message = "Warning: Tag [END;] not found." + Environment.NewLine + ParsedLog.ParseResult.Message ParsedLog.ParseResult.Message_Rus = "Предупреждение: Ключевое слово [END;] не найдено." + Environment.NewLine + ParsedLog.ParseResult.Message_Rus End If If ParsedLog.ParseResult.Type <> LOG_PARSE_ERROR_TYPE.FORMATTED_LOG_NOT_FOUND Then If ParsedLog.GetHeaderValue("PBand") = String.Empty Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND ParsedLog.ParseResult.Message = "Critical error: <PBand> tag not found." + Environment.NewLine + ParsedLog.ParseResult.Message ParsedLog.ParseResult.Message_Rus = "Критическая ошибка: Ключевое слово <PBand> не найдено, не указан диапазон." + Environment.NewLine + ParsedLog.ParseResult.Message_Rus End If End If If ParsedLog.ParseResult.Type <> LOG_PARSE_ERROR_TYPE.FORMATTED_LOG_NOT_FOUND _ And ParsedLog.ParseResult.Type <> LOG_PARSE_ERROR_TYPE.OTHER_CONTEST Then CheckHeaders_ContestSensitive() GetCategory() If ParsedLog.Callsign = String.Empty Then ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.ERRORS_FOUND ParsedLog.ParseResult.Message = "Critical error: <PCall> tag not found or your callsign is incorrect." + Environment.NewLine + ParsedLog.ParseResult.Message ParsedLog.ParseResult.Message_Rus = "Критическая ошибка: Ключевое слово <PCall> не найдено или же позывной указан некорректно." + Environment.NewLine + ParsedLog.ParseResult.Message_Rus Else ParsedLog.ParseResult.Message = "Your callsign is detected as: " + ParsedLog.Callsign + Environment.NewLine + ParsedLog.ParseResult.Message ParsedLog.ParseResult.Message_Rus = "Определен ваш позывной: " + ParsedLog.Callsign + Environment.NewLine + ParsedLog.ParseResult.Message_Rus End If End If End If If ParsedLog.ParseResult.Type <> LOG_PARSE_ERROR_TYPE.NONE Then If If(Parameters.HelpText, String.Empty) <> String.Empty Then ParsedLog.ParseResult.Message_Rus += Environment.NewLine + Parameters.HelpText If If(Parameters.HelpTextEn, String.Empty) <> String.Empty Then ParsedLog.ParseResult.Message += Environment.NewLine + Parameters.HelpTextEn End If If (ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.NONE _ Or ParsedLog.ParseResult.Type = LOG_PARSE_ERROR_TYPE.WARNING) _ And If(Parameters.ResultsLink, String.Empty) <> String.Empty Then ParsedLog.ParseResult.Message_Rus += Environment.NewLine + "Ознакомьтесь с результатами по адресу " + Parameters.ResultsLink ParsedLog.ParseResult.Message += Environment.NewLine + "Check results at " + Parameters.ResultsLink End If ParsedLog.Encoding = encoding ParsedLog.QSOCount = QSOCount ParsedLog.Format = LOG_FORMAT.EDI End Sub ''' <summary> ''' Поиск значения тега по тегу и вывод количества строк с данным тегом ''' </summary> Private Function GetHeaderValue(HeaderFields As Collection, Name As String, Count As Integer, Optional ByRef Value As String = "") As Integer Dim Res As Integer = 0 Value = String.Empty For Each Header As clsParsedHeader In HeaderFields If Header.Name.ToUpper = Name.ToUpper Then Res += 1 If Res <= Count _ Or Count = 0 Then If Header.Value <> String.Empty Then If Value = String.Empty Then Value = Header.Value Else Value += Environment.NewLine + Header.Value End If End If End If End If Next Return Res End Function ''' <summary> ''' Проверка заголовков в зависимости от контеста ''' </summary> Private Sub CheckHeaders_ContestSensitive() If Not Me.HeaderFields Is Nothing Then Select Case Me.Parameters.ContestName End Select End If End Sub ''' <summary> ''' Проверка QSO в зависимости от контеста ''' </summary> Private Sub CheckQSO_ContestSensitive(QSO As clsParsedQSO) If Not QSO Is Nothing Then If Me.Parameters.ContestName = "VHF-ACTIVITY" Then If QSO.Time < Me.Parameters.DateStart _ Or QSO.Time > Me.Parameters.DateEnd Then QSO.ParseResult.Message += Environment.NewLine + " " + "Error: invalid date and/or time: " + SpecialTimeFormat(QSO.Time) + ". " _ + Environment.NewLine + " " + "The contest was spending from " + SpecialTimeFormat(Me.Parameters.DateStart) + " till " _ + SpecialTimeFormat(Me.Parameters.DateEnd) + ". " QSO.ParseResult.Message_Rus += Environment.NewLine + " " + "Ошибка: неверное время и/или дата: " + SpecialTimeFormat(QSO.Time) + ". " _ + Environment.NewLine + " " + "Соревнования проводились с " + SpecialTimeFormat(Me.Parameters.DateStart) + " по " _ + SpecialTimeFormat(Me.Parameters.DateEnd) + ". " If QSO.ParseResult.Type = PARSE_ERROR_TYPE.NONE Then QSO.ParseResult.Type = PARSE_ERROR_TYPE.BAD End If End If Else If QSO.Time < Me.Parameters.DateStart _ Or QSO.Time > Me.Parameters.DateEnd Then QSO.ParseResult.Message += Environment.NewLine + " " + "Warning: invalid date and/or time: " + SpecialTimeFormat(QSO.Time) + ". " _ + Environment.NewLine + " " + "The contest was spending from " + SpecialTimeFormat(Me.Parameters.DateStart) + " till " _ + SpecialTimeFormat(Me.Parameters.DateEnd) + ". " QSO.ParseResult.Message_Rus += Environment.NewLine + " " + "Предупреждение: неверное время и/или дата: " + SpecialTimeFormat(QSO.Time) + ". " _ + Environment.NewLine + " " + "Соревнования проводились с " + SpecialTimeFormat(Me.Parameters.DateStart) + " по " _ + SpecialTimeFormat(Me.Parameters.DateEnd) + ". " If QSO.ParseResult.Type = PARSE_ERROR_TYPE.NONE Then QSO.ParseResult.Type = PARSE_ERROR_TYPE.WARNING End If End If End If Select Case Me.Parameters.ContestName Case "SPB-OPEN-VHF" Case "VHF-ACTIVITY" Dim BadDate As Boolean = False Dim StartTime As Date Dim EndTime As Date If Weekday(QSO.Time, FirstDayOfWeek.Monday) <> 2 Then BadDate = True Else Select Case QSO.Band Case "144" If Day(QSO.Time) >= 8 Then BadDate = True End If Case "432" If Day(QSO.Time) <= 7 _ Or Day(QSO.Time) >= 15 Then BadDate = True End If Case "1,3G" If Day(QSO.Time) <= 14 _ Or Day(QSO.Time) >= 22 Then BadDate = True End If End Select End If If BadDate Then QSO.ParseResult.Message += Environment.NewLine + " " + "Warning: invalid date: " + SpecialTimeFormat(QSO.Time) + ". " _ + Environment.NewLine + " " + "The contest is held on Tuesdays." QSO.ParseResult.Message_Rus += Environment.NewLine + " " + "Предупреждение: неверная дата: " + SpecialTimeFormat(QSO.Time) + ". " _ + Environment.NewLine + " " + "Дни активности проводятся по вторникам. Первый вторник месяца - 144 МГц, второй - 432 МГц, третий - 1296 МГц." QSO.ParseResult.Type = PARSE_ERROR_TYPE.BAD Else If Month(QSO.Time) >= 4 _ And Month(QSO.Time) <= 10 Then StartTime = QSO.Time.Date.AddHours(17) EndTime = QSO.Time.Date.AddHours(21) Else StartTime = QSO.Time.Date.AddHours(18) EndTime = QSO.Time.Date.AddHours(22) End If If QSO.Time < StartTime _ Or QSO.Time >= EndTime Then BadDate = True QSO.ParseResult.Message += Environment.NewLine + " " + "Warning: invalid date and/or time: " + SpecialTimeFormat(QSO.Time) + ". " _ + Environment.NewLine + " " + "The contest is spending from " + SpecialTimeFormat(StartTime) + " till " _ + SpecialTimeFormat(EndTime) + ". " QSO.ParseResult.Message_Rus += Environment.NewLine + " " + "Предупреждение: неверное время и/или дата: " + SpecialTimeFormat(QSO.Time) + ". " _ + Environment.NewLine + " " + "Соревнования проводятся с " + SpecialTimeFormat(StartTime) + " по " _ + SpecialTimeFormat(EndTime) + ". " If QSO.ParseResult.Type = PARSE_ERROR_TYPE.NONE Then QSO.ParseResult.Type = PARSE_ERROR_TYPE.WARNING End If End If End If End Select End If End Sub ''' <summary> ''' Получение и проверка категории в зависимости от контеста ''' </summary> Private Sub GetCategory() Dim Category As String = String.Empty Dim Incorrect_Category As Boolean = False Dim ErrorFound As Boolean = False If Me.Parameters.ContestName = "VHF-ACTIVITY" Then If Not ParsedLog.ContestDate Is Nothing Then Category = Right("0" + Month(ParsedLog.ContestDate.Value).ToString, 2) + Space(1) + ParsedLog.Band If Left(ParsedLog.Callsign, 1) = "R" _ Or (Left(ParsedLog.Callsign, 2) >= "UA" And Left(ParsedLog.Callsign, 2) <= "UI") _ Or Left(ParsedLog.Callsign, 2) = "U1" _ Or Left(ParsedLog.Callsign, 2) = "U3" Then Category = Category Else Category = Category + " Foreign" End If End If Else If Not Me.HeaderFields Is Nothing Then Select Case Me.Parameters.ContestName Case Else GetHeaderValue(Me.HeaderFields, "PSect", 1, Category) ParsedLog.Category = Category End Select End If If InStr(Category, "A2") > 0 Or InStr(Category, "B2") > 0 _ Or InStr(Category, "144") > 0 Then Category = "144" ElseIf InStr(Category, "A0") > 0 Or InStr(Category, "B0") > 0 _ Or InStr(Category, "MULTI OP") > 0 Or InStr(Category, "MULTI-OP") > 0Then Category = "MULTI-OP" ElseIf InStr(Category, "A1") > 0 Or InStr(Category, "B1") > 0 _ Or InStr(Category, "SINGLE OP") > 0 Or InStr(Category, "SINGLE OP") > 0 Or Category = "SO" Then Category = "SINGLE-OP" ElseIf InStr(Category, "LIMITED") > 0 Or InStr(Category, "A3") > 0 Or InStr(Category, "B3") > 0 Then Category = "SINGLE-OP LIMITED" ElseIf InStr(Category, "CHECK") > 0 Then Category = "CHECKLOG" Else Category = "SINGLE-OP" End If End If If Not ErrorFound Then ParsedLog.Category = Category If Parameters.ContestName <> "VHF-ACTIVITY" Then ParsedLog.ParseResult.Message = "Your category is detected as: " + ParsedLog.Category + Environment.NewLine + ParsedLog.ParseResult.Message ParsedLog.ParseResult.Message_Rus = "Определена ваша заявленная подгруппа: " + ParsedLog.Category + Environment.NewLine + ParsedLog.ParseResult.Message_Rus End If End If End Sub ''' <summary> ''' Проверка корректности позывного (содержит только заглавные английские буквы, цифры и дробь) ''' </summary> Private Function IsValidCallsign(CallSign As String) As Boolean Dim Res As Boolean If CallSign.Length > 2 Then For i As Integer = 1 To CallSign.Length Dim ch As Char = CChar(Mid(CallSign, i, 1)) If (ch >= "A" And ch <= "Z") _ Or (ch >= "0" And ch <= "9") _ Or ch = "/" _ Or ch = "-" Then Res = True Else Res = False Exit For End If Next Else Res = False End If Return Res End Function ''' <summary> ''' Проверка корректности рапорта ''' </summary> Private Function IsValidReport(Report As String) As Boolean Dim Res As Boolean = False If Report.Length >= 2 _ And Report.Length <= 3 _ And Not Report.Contains("0") Then If IsNumeric(Report) Then If (CInt(Report) >= 11 And CInt(Report) <= 59) _ Or (CInt(Report) >= 111 And CInt(Report) <= 599) Then Res = True End If ElseIf IsNumeric(Left(Report, 2)) Then If (CInt(Left(Report, 2)) >= 11 And CInt(Left(Report, 2)) <= 59) Then Res = True End If End If End If Return Res End Function ''' <summary> ''' Проверка корректности вида работы ''' </summary> ''' <param name="EdiModeCode">Цифровой код вида работы</param> ''' <param name="Mode_Out"></param> ''' <returns></returns> ''' <remarks></remarks> Private Function IsValidMode(EdiModeCode As String, ByRef Mode_Out As String) As Boolean Dim Res As Boolean = True If EdiModeCode = "1" Then Mode_Out = "SSB" ElseIf EdiModeCode = "2" Then Mode_Out = "CW" ElseIf EdiModeCode = "6" Then Mode_Out = "FM" Else Res = False End If Return Res End Function ''' <summary> ''' Проверка корректности позывного (содержит только заглавные английские буквы, цифры и дробь) ''' </summary> Private Function IsValidLocator(Locator As String) As Boolean Dim Res As Boolean If Locator.Length = 6 Then Dim RX As New Text.RegularExpressions.Regex("\p{Lu}{2}\d{2}\p{Lu}{2}") Res = RX.Matches(Locator).Count = 1 Else Res = False End If Return Res End Function Private Function SpecialTimeFormat(Value As Date) As String Dim Res As String Res = Value.Year.ToString + "-" + Right("0" + Value.Month.ToString, 2) + "-" + Right("0" + Value.Day.ToString, 2) + " " + Right("0" + Value.Hour.ToString, 2) + ":" + Right("0" + Value.Minute.ToString, 2) Return Res End Function Private Function CheckDateFormat(DateString As String, ByRef DateOut As DateTime) As Boolean Dim Result As Boolean = False Dim yy As String Dim mm As String Dim dd As String If DateString.Length = 6 Then yy = Mid(DateString, 1, 2) mm = Mid(DateString, 3, 2) dd = Mid(DateString, 5, 2) If IsNumeric(yy) _ AndAlso IsNumeric(mm) _ AndAlso IsNumeric(dd) _ AndAlso IsNumeric(yy) _ AndAlso mm <> String.Empty _ AndAlso dd <> String.Empty _ AndAlso yy <> String.Empty _ AndAlso (CInt(mm) > 0 And CInt(mm) < 13) _ AndAlso (CInt(dd) > 0 And CInt(dd) < 32) Then DateOut = DateSerial(CInt(yy), CInt(mm), CInt(dd)) Result = True End If End If Return Result End Function Private Function CheckTimeFormat(TimeString As String, ByRef DateOut As DateTime) As Boolean Dim Result As Boolean = False Dim hh As String Dim nn As String hh = Mid(TimeString, 1, 2) nn = Mid(TimeString, 3, 2) If IsNumeric(hh) _ AndAlso IsNumeric(nn) _ AndAlso IsNumeric(nn) _ AndAlso nn <> String.Empty _ AndAlso hh <> String.Empty _ AndAlso (CInt(nn) < 60 And CInt(nn) >= 0) _ AndAlso (CInt(hh) < 24 And CInt(hh) >= 0) Then DateOut = DateAdd(DateInterval.Minute, CInt(nn), DateOut) DateOut = DateAdd(DateInterval.Hour, CInt(hh), DateOut) Result = True End If Return Result End Function ''' <summary> ''' Форматирование порядкового номера 1 => 001 ''' </summary> ''' <param name="Nr"></param> ''' <returns></returns> ''' <remarks></remarks> Private Function FormatSerialNr(Nr As String) As String Dim Res As String = "000" If IsNumeric(Nr) Then If CInt(Nr) >= 1000 Then Res = Nr Else Res = Right("000" + CInt(Nr).ToString, 3) End If End If Return Res End Function #End Region End Class #End Region End Namespace