I have written the below mentioned code but its not functional. Can anyone help?
Explanation:
A 7 or 8 digit number is set. If the number is 8 digits, the first 2 numbers are removed, if the number is 7 digits, the first number is removed. A 6 digit number is left whereby every digit can be repeated without any constraints. So one can have a number between 000001 and 999999. (Zeros on the left are counted).
The code is functional on the first 3 digits but does not function properly later on though i'm using the same logic. The function of the code is to Generate all possible patterns by translating the numbers into characters.
The constraints:
Letters used are only a, b, c, d, e, and f.
Characters should run systematic order
Under this logic:
The pattern can range between aaaaaa and abcdef.
The first character is always "a" and the last character could be "f" in case all digits are different from one another.
So, the number 454657 is translated to abacbd or 123456 is translated to abcdef. (c Can't exist if there is no b and d can't exist if there is no b and c).
Private Sub CommandButton1_Click()
Dim GSM_Counter, GSM, GSM_Range, a, b, c, d, e, f As String
Dim GSM_length, Num1, Num2, Num3, Num4, Num5, Num6, a1, b1, c1, d1, e1, f1 As integer
GSM_Counter = Application.WorksheetFunction.CountA(Range("A:A"))
For i = 2 To GSM_Counter
GSM_length = Len(Range("A" & i))
Select Case GSM_length
Case Is = 8
Range("B" & i) = Left(Range("A" & i), 2)
Num1 = Right(Left(Range("A" & i), 3), 1)
Num2 = Right(Left(Range("A" & i), 4), 1)
Num3 = Right(Left(Range("A" & i), 5), 1)
Num4 = Right(Left(Range("A" & i), 6), 1)
Num5 = Right(Left(Range("A" & i), 7), 1)
Num6 = Right(Left(Range("A" & i), 8), 1)
Case Is = 7
Range("B" & i) = Left(Range("A" & i), 1)
Num1 = Right(Left(Range("A" & i), 2), 1)
Num2 = Right(Left(Range("A" & i), 3), 1)
Num3 = Right(Left(Range("A" & i), 4), 1)
Num4 = Right(Left(Range("A" & i), 5), 1)
Num5 = Right(Left(Range("A" & i), 6), 1)
Num6 = Right(Left(Range("A" & i), 7), 1)
End Select
Range("C" & i) = Num1
Range("D" & i) = Num2
Range("E" & i) = Num3
Range("F" & i) = Num4
Range("G" & i) = Num5
Range("H" & i) = Num6
Next i
For k = 2 To GSM_Counter
a1 = Range("C" & k)
b1 = Range("D" & k)
c1 = Range("E" & k)
d1 = Range("F" & k)
e1 = Range("G" & k)
f1 = Range("H" & k)
a = "a"
Range("K" & k) = a
If b1 = a1 Then
b = "a"
Else
b = "b"
End If
Range("L" & k) = b
If c1 = a1 Then
c = "a"
ElseIf c1 = b1 Then
c = "b"
Else
c = "c"
End If
Range("M" & k) = c
If d1 = a1 Then
d = "a"
ElseIf d1 = b1 Then
d = "b"
ElseIf d1 = c1 Then
d = "c"
Else
d = "d"
End If
Range("N" & k) = d
If e1 = a1 Then
e = "a"
ElseIf e1 = b1 Then
e = "b"
ElseIf e1 = c1 Then
e = "c"
ElseIf e1 = d1 Then
e = "d"
Else
e = "e"
End If
Range("O" & k) = e
If f1 = a1 Then
f = "a"
ElseIf f1 = b1 Then
f = "b"
ElseIf f1 = c1 Then
f = "c"
ElseIf f1 = d1 Then
f = "d"
ElseIf f1 = e1 Then
f = "e"
Else
f = "f"
End If
Range("P" & k) = f
Next k
End Sub
Here is another way..
'~~> Test Data
Sub Sample()
Dim TestArray(1 To 6) As Long
Dim i As Long
TestArray(1) = 468013: TestArray(2) = 12234455: TestArray(3) = 234523
TestArray(4) = 44444444: TestArray(5) = 123: TestArray(6) = 111222
For i = 1 To 6
Debug.Print TestArray(i) & " --> " & Encrypt(TestArray(i))
Next i
End Sub
'~~> Actual Function
Function Encrypt(n As Long) As String
Dim j As Long, k As Long, sNum As String
sNum = Format(CLng(Right(n, 6)), "000000")
j = 97
For k = 1 To 6
If IsNumeric(Mid(sNum, k, 1)) Then
sNum = Replace(sNum, Mid(sNum, k, 1), Chr(j))
j = j + 1
End If
Next k
Encrypt = sNum
End Function
Output
468013 --> abcdef
12234455 --> abccdd
234523 --> abcdab
44444444 --> aaaaaa
123 --> aaabcd
111222 --> aaabbb
EDIT:
If you are planning to use it as a worksheet function and you are not sure what kind of input will be there then change
Function Encrypt(n As Long) As String
to
Function Encrypt(n As Variant) As String
I would suggest getting to know the Chr() and possibly the Asc() VBA functions along with a general knowledge of how digits and alphabetic characters translate to ASCII code characters. I may be reading things wrong but I thought I saw some contradictions between the examples, your description and the actual code provided. Here is one method putting the pattern generation into a User Defined Function or UDF.
Function num_2_alpha(sNUM As String)
'ASCII 0-9 = 46-57, a-z = 97-122
Dim tmp As String, i As Long, c As Long
sNUM = Right(sNUM, 6)
tmp = Chr(97) ' =a
For i = 2 To 6
If CBool(InStr(1, Left(sNUM, i - 1), Mid(sNUM, i, 1))) Then
tmp = tmp & Mid(tmp, InStr(1, Left(sNUM, i - 1), Mid(sNUM, i, 1)), 1)
Else
'tmp = tmp & Chr(i + 96)
c = c + 1
tmp = tmp & Chr(c + 97) 'alternate (code) method
End If
Next i
num_2_alpha = tmp
End Function
Note that I've offered an alternate method that is commented out. Either that line or the one above it should be active; never both at one time. These were the results generated.
Addendum: I believe my recent edit should help conform to the examples you left in comments. Code and image updated.
Related
I am struggling to grasp the concept of describing a regular expression for a 3 alphabet language where the only restriction is on all three characters appearing in one specific order.
eg1 :
Write a regular expression over \S = {a, b, c} which ensures that w is such that there is no occurrence of the string "abc"
Valid matches include {bac, baac, cad, aaaaccb, abababac} the only word that should not be produced is "abc"
eg2 :
Write a regular expression over \S = {x, y, z} which ensures that w is such that there is no occurrence of the string "zyx"
Valid matches include {xyz, xyyx, yzx, zzyyxc, xyxyxzyzy} the only word that should not be produced is "zyx"
We can make a DFA first and then run the algorithm to make the regular expression.
A DFA for the first is:
q s q'
----------------
q0 b,c q0
q0 a q1
q1 a q1
q1 b q2
q1 c q0
q2 a q1
q2 b q0
q2 c q3
q3 a,b,c q3
We can write some equations...
q0 = q0(b + c) + q1c + q2b
q1 = q0a + q1a + q2a
q2 = q1b
We can replace all instances of q2 with q1b ...
q0 = q0(b + c) + q1(c + bb)
q1 = q0a + q1(a + ba)
q2 = q1b
We can remove the recursion in the equation for q1:
q0 = q0(b + c) + q1(c + bb) + e
q1 = q0a(a + ba)*
q2 = q1b
Now replace the expression for q1 ...
q0 = q0((b + c) + a(a + ba)*(c + bb)) + e
q1 = q0a(a + ba)*
q2 = q1b
Removing the recursion from the equation for q0 gives:
q0 = ((b + c) + a(a + ba)*(c + bb))*
q1 = q0a(a + ba)*
q2 = q1b
Filling in the others gives
q0 = ((b + c) + a(a + ba)*(c + bb))*
q1 = ((b + c) + a(a + ba)*(c + bb))*a(a + ba)*
q2 = ((b + c) + a(a + ba)*(c + bb))*a(a + ba)*b
Since these three states are accepting, our RE should be the union:
r = ((b + c) + a(a + ba)*(c + bb))*(e + a(a + ba)*(e + b))
Your other example is quite similar.
I have a VB 5.0 code that does what I need, but I need to implement it in Visual Studio C++ (2013), the thing is that I'm not getting there, and I have no idea what I'm doing wrong, so I'll show you some code (VB vs C++ - mine) and hope someone is able to help.
For now, thank you for reading this.
I've tried to send the string in very different formats and I think that I finally got it, in how to send, the problem still is reading the answer, I have no idea what I'm doing wrong.
The machine returns (I think 2 bytes) and they are START OF HEADING and ?, I can see it by printing in the console the numbers 1 and 63.
I'll just leave some code.
For asking the current temperature the VB program is:
Private Sub cmdGetTemperaturePV_Click()
If MSComm.PortOpen Then
MSComm.Output = Chr(1) & Chr(0) & Chr(0) & Chr(1) & Chr(13) & Chr(10)
txtMsg(1).Text = "1,0,0,1,13,10"
txtPVTemperature.Text = ""
Else
txtMsg(1).Text = "COM Port OFF"
Beep
End If
End Sub
And mine(C++) is:
String^ a1 = "\x1";
String^ a2 = "\x0";
String^ a3 = "\x0";
String^ a4 = "\x1";
String^ a5 = "\xD";
String^ a6 = "\xA";
String^ enviar = a1 + a2 + a3 + a4 + a5 + a6;
this->serialPort1->Write(enviar);
By using the program "Hercules" I can simulate the reception of the machine and I can see that I'm sending exactly the same thing as the VB program.
Now I think that the problem is receiving, so about that, there's this:
Private Sub tmrRun_Timer()
Dim i As Integer
Dim apt As Byte, B1 As Byte, B2 As Byte
Dim stx As String
If MSComm.PortOpen Then
If MSComm.InBufferCount >= 6 Then
stx = MSComm.Input
stx = Right(stx, 6)
txtMsg(2).Text = ""
For i = 1 To Len(stx)
txtMsg(2).Text = txtMsg(2).Text & Asc(Mid(stx, i, 1)) & ","
Next i
txtMsg(2).Text = Left(txtMsg(2).Text, Len(txtMsg(2).Text) - 1)
apt = Asc(Left(stx, 1))
B1 = Asc(Mid(stx, 2, 1))
B2 = Asc(Mid(stx, 3, 1))
Select Case apt
Case 1:
txtPVTemperature.Text = Format(0.1 * GetInt(B1, B2), "0.0")
Case 2:
txtSPTemperature.Text = Format(0.1 * GetInt(B1, B2), "0.0")
Case 3:
Case 4:
txtPVHumidity.Text = Format(0.1 * GetInt(B1, B2), "0.0")
Case 5:
txtSPHumidity.Text = Format(0.1 * GetInt(B1, B2), "0.0")
Case 6:
Case 7:
Case 8:
Case 9:
If Asc(Mid(stx, 2, 1)) > 0 Then
txtChamber.Text = "ON"
Else
txtChamber.Text = "OFF"
End If
Case 10:
txtEvents.Text = GetInt(B1, B2)
Case 11:
Case 12:
txtInputs.Text = "1..8 = " & B1 & " 9..16 = " & B2
Case 13:
txtAlarms1.Text = " 1.. 8 = " & B1 & " 9..16 = " & B2
Case 14:
txtAlarms2.Text = "17..24 = " & B1 & " 25..32 = " & B2
End Select
End If
End If
End Sub
And I'm trying many different things, the best I got (the one that led me to 1 and 63) is this:
{
String^ rec;
if (this->serialPort1->IsOpen)
{
this->textBox1->Text = String::Empty;
try
{
rec = this->serialPort1->ReadExisting();
}
catch (TimeoutException^)
{
this->textBox2->Text = "Timeout";
}
}
this->textBox1->Text = rec;
char aux[100];
if (rec == String::Empty)
this->textBox2->Text = "String Empty";
else
{
std::string rec1 = marshal_as<std::string>(rec);
strcpy(aux, rec1.c_str());
int a, b, c, d, e1, f;
printf("String received: ");
for (int i = 0; i < 6; i++)
{
if (aux[i] == 0)
break;
printf("%ld ", aux[i]);
if (i == 0)
a = aux[i];
if (i == 1)
b = aux[i];
if (i == 2)
c = aux[i];
if (i == 3)
d = aux[i];
if (i == 4)
e1 = aux[i];
if (i == 5)
f = aux[i];
}
}
}
I'm expecting to receive a 6 byte string and It's not happening.
I'm so sorry for the long post, but I think this way I can be more specific.
Again, thank you very much!
I have a column where each cell has a string of digits, ?, -, and digits in parentheses/brackets/curly brackets. A good example would be something like the following:
3????0{1012}?121-2[101]--01221111(01)1
How do I separate the string into different cells by characters, where a 'character' in this case refers to any number, ?, -, and value within the parentheses/brackets/curly brackets (including said parentheses/brackets/curly brackets)?
In essence, the string above would turn into the following (spaced apart to denote a separate cell):
3 ? ? ? ? 0 {1012} ? 1 2 1 - 2 [101] - - 0 1 2 2 1 1 1 1 (01) 1
The amount of numbers within the parentheses/brackets/curly brackets vary. There are no letters in any of the strings.
Here you are!
RegEx method:
Sub Test_RegEx()
Dim s, col, m
s = "3????0{1012}?121-2[101]--01221111(01)1"
Set col = CreateObject("Scripting.Dictionary")
With CreateObject("VBScript.RegExp")
.Global = True
.Pattern = "(?:\d|-|\?|\(\d+\)|\[\d+\]|\{\d+\})"
For Each m In .Execute(s)
col(col.Count) = m
Next
End With
MsgBox Join(col.items) ' 3 ? ? ? ? 0 {1012} ? 1 2 1 - 2 [101] - - 0 1 2 2 1 1 1 1 (01) 1
End Sub
Loop method:
Sub Test_Loop()
Dim s, col, q, t, k, i
s = "3????0{1012}?121-2[101]--01221111(01)1"
Set col = CreateObject("Scripting.Dictionary")
q = "_"
t = True
k = 0
For i = 1 To Len(s)
t = (t Or InStr(1, ")]}", q) > 0) And InStr(1, "([{", q) = 0
q = Mid(s, i, 1)
If t Then k = k + 1
col(k) = col(k) & q
Next
MsgBox Join(col.items) ' 3 ? ? ? ? 0 {1012} ? 1 2 1 - 2 [101] - - 0 1 2 2 1 1 1 1 (01) 1
End Sub
Something else to look at :)
Sub test()
'String to parse through
Dim aStr As String
'final string to print
Dim finalString As String
aStr = "3????0{1012}?121-2[101]--01221111(01)1"
'Loop through string
For i = 1 To Len(aStr)
'The character to look at
char = Mid(aStr, i, 1)
'Check if the character is an opening brace, curly brace, or parenthesis
Dim result As String
Select Case char
Case "["
result = loop_until_end(Mid(aStr, i + 1), "]")
i = i + Len(result)
result = char & result
Case "("
result = loop_until_end(Mid(aStr, i + 1), ")")
i = i + Len(result)
result = char & result
Case "{"
result = loop_until_end(Mid(aStr, i + 1), "}")
i = i + Len(result)
result = char & result
Case Else
result = Mid(aStr, i, 1)
End Select
finalString = finalString & result & " "
Next
Debug.Print (finalString)
End Sub
'Loops through and concatenate to a final string until the end_char is found
'Returns a substring starting from the character after
Function loop_until_end(aStr, end_char)
idx = 1
If (Len(aStr) <= 1) Then
loop_until_end = aStr
Else
char = Mid(aStr, idx, 1)
Do Until (char = end_char)
idx = idx + 1
char = Mid(aStr, idx, 1)
Loop
End If
loop_until_end = Mid(aStr, 1, idx)
End Function
Assuming the data is in column A starting in row 1 and that you want the results start in column B and going right for each row of data in column A, here is alternate method using only worksheet formulas.
In cell B1 use this formula:
=IF(OR(LEFT(A1,1)={"(","[","{"}),LEFT(A1,MIN(FIND({")","]","}"},A1&")]}"))),IFERROR(--LEFT(A1,1),LEFT(A1,1)))
In cell C1 use this formula:
=IF(OR(MID($A1,SUMPRODUCT(LEN($B1:B1))+1,1)={"(","[","{"}),MID($A1,SUMPRODUCT(LEN($B1:B1))+1,MIN(FIND({")","]","}"},$A1&")]}",SUMPRODUCT(LEN($B1:B1))+1))-SUMPRODUCT(LEN($B1:B1))),IFERROR(--MID($A1,SUMPRODUCT(LEN($B1:B1))+1,1),MID($A1,SUMPRODUCT(LEN($B1:B1))+1,1)))
Copy the C1 formula right until it starts giving you blanks (there are no more items left to split out from the string in the A cell). In your example, need to copy it right to column AA. Then you can copy the formulas down for the rest of your Column A data.
Am converting some C++ code to VB.NET and need to convert assignments within expressions. Below are some C++ lines of code for which it's not clear what the converted results would be:
i2 = 1 + (i1 = i + i)
i4 = 1 + (i3 = n - i1)
wr = (wtemp = wr) * wpr - wi * wpi + wr
data(0) = (h1r = data(0)) + data(1)
data(0) = c1 * ((h1r = data(0)) + data(1))
Would the first line translate to:
If i2 = 1 Then i1 = i + i
?
Hans gave you the procedure - but just in case there's still any doubt about how to do this, your final result should be:
i1 = i + i
i2 = 1 + i1
i3 = n - i1
i4 = 1 + i3
wtemp = wr
wr = wtemp * wpr - wi * wpi + wr
h1r = data(0)
data(0) = h1r + data(1)
h1r = data(0)
data(0) = c1 * (h1r + data(1))
The code is already converted to VB.NET!
For example if you look at the following VB.NET code
Dim i2 As Int16
Dim i1 As Int16
Dim i As Int16
Dim data(0 To 1)
i = 1
i1 = 1
i2 = 0
i2 = 1 + (i1 = i + i) 'Same as your C++ code
MsgBox(i2)
It will return 1. The code translates to
i2 = 1 + (if i1= i+i)
I solved my problem in an imperative style, but it looks very ugly. How can I make it better (more elegant, more concise, more functional - finally its Scala). Rows with the same values as the previous row, but with a different letter should be skipped, all other values of the rows should be added.
val row1 = new Row(20, "A", true) // add value
val row2 = new Row(30, "A", true) // add value
val row3 = new Row(40, "A", true) // add value
val row4 = new Row(40, "B", true) // same value as the previous element & different letter -> skip row
val row5 = new Row(60, "B", true) // add value
val row6 = new Row(70, "B", true) // add value
val row7 = new Row(70, "B", true) // same value as the previous element, but the same letter -> add value
val rows = List(row1, row2, row3, row4, row5, row6, row7)
var previousLetter = " "
var previousValue = 0.00
var countSkip = 0
for (row <- rows) {
if (row.value == previousValue && row.letter != previousLetter) {
row.relevant = false
countSkip += 1
}
previousLetter = row.letter
previousValue = row.value
}
// get sum
val sumValue = rows.filter(_.relevant == true).map(_.value) reduceLeftOption(_ + _)
val sum = sumValue match {
case Some(d) => d
case None => 0.00
}
assert(sum == 290)
assert(countSkip == 1)
Thanks in advance
Twistleton
(rows.head :: rows).sliding(2).collect{
case List(Row(v1,c1), Row(v2,c2)) if ! (v1 == v2 && c1 != c2) => v2 }.sum
I think the shortest (bulletproof) solution when Row is a case class (dropping the boolean) is
(for ((Row(v1,c1), Row(v2,c2)) <- (rows zip rows.take(1) ::: rows) if (v1 != v2 || c1 == c2)) yield v1).sum
Some of the other solutions don't handle the list-is-empty case, but this is largely because sliding has a bug where it will return a partial list if the list is too short. Clearer to me (and also bulletproof) is:
(rows zip rows.take(1) ::: rows).collect{
case (Row(v1,c1), Row(v2,c2)) if (v1 != v2 || c1 == c2) => v1
}.sum
(which is only two characters longer if you keep it on one line). If you need the number skipped also,
val indicated = (rows zip rows.take(1) ::: rows).collect {
case (Row(v1,c1), Row(v2,c2)) => (v1, v1 != v2 || c1 == c2)
}
val countSkip = indicated.filterNot(_._2).length
val sum = indicated.filter(_._2).map(_._1).sum
Fold it:
scala> rows.foldLeft((row1, 0))((p:(Row,Int), r:Row) => (r, p._2 + (if (p._1.value == r.value && p._1.letter != r.letter) 0 else r.value)))._2
res2: Int = 290
(new Row(0, " ", true) +: rows).sliding(2).map { case List(r1, r2) =>
if (r1.value != r2.value || r1.letter == r2.letter) { r2.value }
else { 0 }
}.sum
Of course you can drop the boolean member of Row if you do not need it for something else
Reduce it:
rows.reduceLeft { (prev, curr) =>
if (prev.value == curr.value && prev.letter != curr.letter) {
curr.relevant = false
countSkip += 1
}
curr
}