Files
EgtWPFLib/FractionStringConverter.vb
2023-02-16 15:45:19 +01:00

265 lines
11 KiB
VB.net

Imports System.Globalization
Imports System.Text.RegularExpressions
Imports EgtUILib
Public Module FractionStringConverter
Public Enum FractionPattern
None
Feet_Inches
Inches
End Enum
' seleziona il tipo di Pattern con cui stamoare i dati
Friend nCurrFractionPattern As FractionPattern = FractionPattern.Feet_Inches
Public Sub SetCurrFractionPattern(nCurrFraction As FractionPattern)
nCurrFractionPattern = nCurrFraction
End Sub
Friend dPrecision As Double = 64
Public Sub SetPrecision(dVal As FractionPattern)
dPrecision = dVal
End Sub
Public Function DoubleToStringFraction(dVal As Double, dBase As Double) As String
Dim sSign As String = String.Empty
If dVal < 0 Then
sSign = "-"
dVal = Math.Abs(dVal)
End If
Dim sFraction As String = String.Empty
' integer and decima part of the value
Dim dInteger As Double = Math.Floor(dVal)
Dim dFraction As Double = dVal - dInteger
' the nearest decimal numerator
Dim dNumeretor As Double = dFraction * dBase
Dim dRound As Double = Math.Round(dNumeretor)
' estimates the irreducible fraction
If dRound = 0 Then
' no decimal part
ElseIf dRound = dBase Then
' no decimal part
dInteger = dInteger + 1
Else
' simplify fraction
While dRound Mod 2 = 0
dRound = dRound / 2
dBase = dBase / 2
End While
sFraction = DoubleToString(dRound, 0) & "/" & DoubleToString(dBase, 0)
End If
' sVal: dFeet'dInteger"sFraction --- dInteger sFraction
Return WriteFraction(sSign, dInteger, sFraction)
End Function
' trasforma il valore da pollici a piedi
Private Sub ConvertInchesToFeet(ByRef dFeet As Double, ByRef dInches As Double)
If dInches = 0 Then Return
While dInches - 12 >= 0
dFeet = dFeet + 1
dInches = dInches - 12
End While
End Sub
' stampa dati in funzione del pattern dichiarato
Private Function WriteFraction(ByVal sSign As String, ByVal dInches As Double, sFraction As String) As String
Dim sVal As String = String.Empty
Select Case nCurrFractionPattern
Case FractionPattern.Feet_Inches
Dim dFeet As Double = 0
ConvertInchesToFeet(dFeet, dInches)
If dFeet <> 0 Then
sVal = String.Format("{0}'{1}""{2}", DoubleToString(dFeet, 0), DoubleToString(dInches, 0), sFraction).Trim
Else
If dInches <> 0 Then
sVal = String.Format("{0}""{1}", DoubleToString(dInches, 0), sFraction).Trim
Else
sVal = String.Format("{0}", sFraction).Trim
End If
End If
Case FractionPattern.Inches
If dInches <> 0 Then
sVal = String.Format("{0}""{1}", DoubleToString(dInches, 0), sFraction).Trim
Else
sVal = String.Format("{0}", sFraction).Trim
End If
End Select
If Not String.IsNullOrEmpty(sVal) Then
sVal = sSign & sVal
End If
Return sVal
End Function
' riceve la stringa sorgente e restituisce la nuova strunga in formato decimale (senza eseguire conversioni di unità)
Public Function OldStringFractionToStringDecimal(sVal As String, ByRef sValConverted As String) As Boolean
Dim dVal As Double = 0
Dim bNegativeValue As Boolean = False
' dato in ingresso: sVal = 2'3"23/32
Dim sFeet As String = String.Empty
Dim sFeetPattern As String = "(.*?)(?=')"
Dim dFeet As Double = 0
Dim bOkFeet As Boolean = True
Dim bFeetExists As Boolean = False
Dim sInch As String = String.Empty
Dim sInchPattern As String = "(?<=')(.*?)(?="")" ' se la stringa contiene l'apice singolo
Dim sInchPattern1 As String = "(.*?)(?="")" ' se la stringa NON contiene l'apice singolo
Dim sInchPattern2 As String = "(.*?)(?=\s+)" ' se la stringa NON contiene l'apice singolo
Dim dInch As Double = 0
Dim bOkInch As Boolean = True
Dim bInchExists As Boolean = False
Dim sFraction As String = String.Empty
Dim sFractionPattern As String = "(?<="")(.*)" ' se la stringa contiene l'apice doppio
Dim sFractionPattern1 As String = "(?<=')(.*)" ' se la stringa NON contiene l'apice doppio ma solo quello singolo
Dim sFractionPattern2 As String = "(?<=\s+)(.*)"
Dim dFraction As Double = 0
Dim bOkFraction As Boolean = True
Dim bFractionExists As Boolean = False
' recupero il valore di Feet (2')
Dim sMyMatch As String = Regex.Match(sVal, sFeetPattern).Groups(1).Value
If Not String.IsNullOrEmpty(sMyMatch) Or Not String.IsNullOrWhiteSpace(sMyMatch) Then
sFeet = sMyMatch.Trim
bOkFeet = StringToDouble(sFeet, dFeet)
bFeetExists = True
End If
' recupero il valore di Inch (3") dopo i Feet - oppure direttamente i pollici
If bFeetExists Then
sMyMatch = Regex.Match(sVal, sInchPattern).Groups(1).Value
Else
sMyMatch = Regex.Match(sVal, sInchPattern1).Groups(1).Value
End If
If Not String.IsNullOrEmpty(sMyMatch) Or Not String.IsNullOrWhiteSpace(sMyMatch) Then
sInch = sMyMatch.Trim
bOkInch = StringToDouble(sInch, dInch)
bInchExists = True
End If
' recupero il valore frazionario (23/32) dopo i pollici - oppure dopo i feet - oppure direttamente i valore inteso come pollici
If bInchExists Then
sMyMatch = Regex.Match(sVal, sFractionPattern).Groups(1).Value
ElseIf bFeetExists And Not bInchExists Then
sMyMatch = Regex.Match(sVal, sFractionPattern1).Groups(1).Value
ElseIf Not bFeetExists And Not bInchExists Then
sMyMatch = sVal
End If
If Not String.IsNullOrEmpty(sMyMatch) Or Not String.IsNullOrWhiteSpace(sMyMatch) Then
sFraction = sMyMatch
bOkFraction = StringToDouble(sFraction, dFraction)
End If
If Not bOkFeet Or Not bOkInch Or Not bOkFraction Then
bOkFeet = True
bOkInch = True
bOkFraction = True
' separo la stringa nello spazio
sMyMatch = Regex.Match(sVal, sInchPattern2).Groups(1).Value
If Not String.IsNullOrEmpty(sMyMatch) Or Not String.IsNullOrWhiteSpace(sMyMatch) Then
sInch = sMyMatch.Trim
bOkInch = StringToDouble(sInch, dInch)
bInchExists = True
End If
sMyMatch = Regex.Match(sVal, sFractionPattern2).Groups(1).Value
If Not String.IsNullOrEmpty(sMyMatch) Or Not String.IsNullOrWhiteSpace(sMyMatch) Then
sFraction = sMyMatch
bOkFraction = StringToDouble(sFraction, dFraction)
End If
End If
' calcolo il valore decimale dell'espressione
If bOkFeet And bOkInch And bOkFraction Then
If dFeet < 0 OrElse dInch < 0 Or dFraction < 0 Then
dVal = -(Math.Abs(dFeet) * 12 + Math.Abs(dInch) + Math.Abs(dFraction))
Else
dVal = dFeet * 12 + dInch + dFraction
End If
sValConverted = DoubleToString(dVal, 4)
Return True
Else
Return False
End If
End Function
Public Function StringFractionToStringDecimal(sVal As String, ByRef sValConverted As String) As Boolean
sValConverted = sVal
' (-?) *(\d */? *\d*')? *(\d* */? *\d+-)? *(\d */? *\d* *""?)? *(\d */? *\d*)?
Dim sPattern As String = "(-?) *(\d */? *\d*')?( *(?(?=\d+ */ *\d+)\d+ */ *\d+|\d+)""?)*"
Dim MyMatchCollection As MatchCollection = Regex.Matches(sVal, sPattern)
For Each MyMatch As Match In MyMatchCollection
Dim bValueExists As Boolean = False
Dim bNegative As Boolean = False
Dim dFeet As Double = 0
Dim bFeet As Boolean = True
Dim dInch As Double = 0
Dim bInch As Boolean = True
Dim dFraction As Double = 0
Dim bFraction As Boolean = True
Dim sCurrValue As String = String.Empty
Dim sCurrValueConverted As String = String.Empty
Dim dCurrValueConverted As Double = 0
For GroupIndex As Integer = 0 To MyMatch.Groups.Count - 1
Dim MyGroup As Group = MyMatch.Groups(GroupIndex)
Dim sGroupVal As String = MyGroup.Value
' verifico che il gruppo non sia vuoto
If Not String.IsNullOrEmpty(sGroupVal) Or Not String.IsNullOrWhiteSpace(sGroupVal) Then
Select Case GroupIndex
Case 0
' se il valore è vuoto allora passo a prossimo Match
If String.IsNullOrEmpty(sGroupVal.Trim) Or String.IsNullOrWhiteSpace(sGroupVal.Trim) Then
Exit For
End If
' salvo il valore del membro dell'espressione che deve essere valutato
sCurrValue = sGroupVal
bValueExists = True
Case 1
' riconosco il segno "-" ad inizio stringa
bNegative = True
Case 2
' riconosco il valore di Feet " ' "
sGroupVal = sGroupVal.Replace("'"c, "")
bFeet = StringToDouble(sGroupVal, dFeet)
Case 3
For CaptureIndex As Integer = 0 To MyGroup.Captures.Count - 1
Dim MyCapture As Capture = MyGroup.Captures(CaptureIndex)
Dim sCapture As String = MyCapture.Value
Select Case CaptureIndex
Case 0
' riconosco il valore in pollici
sCapture = sCapture.Replace(""""c, "")
bInch = StringToDouble(sCapture, dInch)
Case 1
' riconosco il valore di frazione
bFraction = StringToDouble(sCapture, dFraction)
End Select
Next
End Select
End If
Next
If bValueExists And bFeet And bInch And bFraction Then
' ricavo il valore decimale
dCurrValueConverted = dFeet * 12 + dInch + dFraction
If bNegative Then dCurrValueConverted = -dCurrValueConverted
sCurrValueConverted = DoubleToString(dCurrValueConverted, 4)
' sostituisco il valore calcolato nell'espressione iniziale
Dim nStartIndex As Integer = sValConverted.IndexOf(sCurrValue)
sValConverted = sValConverted.Remove(nStartIndex, sCurrValue.Count).Insert(nStartIndex, sCurrValueConverted)
End If
' passo allavalutazione del prossimo membro dell'espressione
Next
Dim dValueConverted As Double = 0
If StringToDouble(sValConverted, dValueConverted) Then
sValConverted = DoubleToString(dValueConverted, 4)
Else
' Errore lettura stringa: sCurrVal non è convertibile
Return False
End If
Return True
End Function
End Module