Bound expressions inside a condition in a cond block in Elixir? - conditional-statements

Is there any way to have multiple bound expressions in a condition in a cond block similar to:
cond do
a = 1; a * 2 == 2 -> "Yes"
end
?
I guess it would be possible if there were something in Elixir like "let in" binding expressions as in Haskell:
let a = 1 in a * 2
Update
In the case below I'd like to bind the String.replace expression to a variable to increase readability (I could of course do it outside the cond which isn't an optimal solution for obvious reasons). The condition checks if the input is upper case only (apart from non-alphabetic characters) and is taken from an exercism.io challenge:
String.upcase(String.replace(input, ~r/[^A-Za-z]/, "")) == String.replace(input, ~r/[^A-Za-z]/, "") and String.length(String.replace(input, ~r/[^A-Za-z]/, "")) > 0 -> "Whoa, chill out!"

To directly answer the first question, the answer is yes. Your original code:
cond do
a = 1; a * 2 == 2 -> "Yes"
end
Is parsed as:
cond do
a = 1
a * 2 == 2 -> "Yes"
end
Because ; means the end of the whole expression. In case you want to include multiple expressions, use parens:
cond do
(a = 1; a * 2 == 2) -> "Yes"
end

Regarding your original question, I think there's nothing wrong with extracting a variable here:
def myfun(input) do
sanitized = String.replace(input, ~r/[^A-Za-z]/, "")
cond do
String.upcase(sanitized) == sanitized and String.length(sanitized) > 0 -> "Whoa, chill out!"
true -> "Good job"
end
end
You could also use the match operator = inside the pattern, more specifically you can use it in place of the first occurrence, but I think it is uglier and harder to read:
def myfun(input) do
cond do
String.upcase(sanitized = String.replace(input, ~r/[^A-Za-z]/, "")) == sanitized and String.length(sanitized) > 0 -> "Whoa, chill out!"
true -> "Good job"
end
end
However your code can be improved by closely looking at the comparisons you are doing. To match the condition, the input string must consist of only uppercase and non-alphabetic characters, containing at least one uppercase character. Since you are already using regexes, here's one that will match all of this in a single check:
\A[^a-z]*[A-Z][^a-z]*\z
Explanation:
\A and \z match string boundaries, the entire string must fulfill the condition
[^a-z]* zero or more non-lowercase characters, followed by
[A-Z] an uppercase character somewhere in the string, followed by
[^a-z]* zero or more non-lowercase characters
Code:
def myfun(input) do
cond do
Regex.match?(~r/\A[^a-z]*[A-Z][^a-z]*\z/, input) -> "Whoa, chill out!"
true -> "Good job"
end
end

Related

What does this code do explanation? VB.NET

If Not (Char.IsDigit(e.KeyChar) Or Char.IsControl(e.KeyChar) Or (e.KeyChar = "." And Not point) Or (e.KeyChar = ",") Or (e.KeyChar = "-" And TQ.SelectionStart = 0))
VB.NET
Part 1
Char.IsDigit(e.KeyChar)
This checks if the current key character is a digit. Documentation on Char.IsDigit: https://learn.microsoft.com/en-us/dotnet/api/system.char.isdigit
Part 2
Char.IsControl(e.KeyChar)
This checks if the current key character is a formatting or other non-printing characters. Documentation on Char.IsControl: https://learn.microsoft.com/en-us/dotnet/api/system.char.iscontrol
Part 3
(e.KeyChar = "." And Not point)
This checks if the current key character is a period, though there is some implicit conversion going on here because KeyChar is a Char type and "." is defined as a String. I'm not sure what point is because you didn't include that definition, but it is most likely a Boolean variable.
Part 4
e.KeyChar = ","
This checks if the current key character is a comma, but again it is implicitly converting the KeyChar to a String.
Part 5
e.KeyChar = "-" And TQ.SelectionStart = 0
This checks if the current key character is a dash, using the implicit conversion. I'm not sure what TQ is because you didn't include that definition, but it is most likely inherited from TextBoxBase since SelectionStart (documentation) is a commonly used property.
Part 6
... Or ... Or ...
These are Or logical operators, it returns the entire grouping of conditions as true if any one of the conditions are true. I would actually suggest using the short-circuit operator OrElse instead. The reason for this is that Or will continue to evaluate the other conditions even if one of the earlier conditions are True when there is no need whereas OrElse will not bother to evaluate the other conditions. For example:
Dim value = 1
If (value = 1 Or value = 2 Or value = 3 Or value = 4) Then
' this does 4 checks because it is using Or, even though the first check was true
End If
If (value = 1 OrElse value = 2 Orelse value = 3 OrElse value = 4) Then
' this does 1 check because it is using OrElse and the first check was true
End If

How can I replace a string without the replace function?

I have a long string of random letters and I need to remove a couple of the front letters a few at a time. By using the replace function, if I replace a piece of string that then repeats later on, it removes the piece of string entirely from the long string instead of just the beginning.
Is there a way to remove a piece of string without using the replace function? The code below might clear up some of the confusion.
Dim protein As String
protein = "GLSDGEWQQVLNVWGKVEADIAGHGQEVLIRLFTGHPETLEKFDKFKHLKTEAEMKASEDLKKHGTVVLTALGGILKKKEGHHEAELKPLAQSHATKHKIPIKYLEFISDAIIHVLHSKHRPGDFGADAQGAMTKALELFRNDIAAKYKELGFQG"
Dim IndexPosition
For Each index In protein
If index = "K" Or index = "R" Then
IndexPosition = InStr(protein, index)
Dim NextPosition = IndexPosition + 1
Dim NextLetter = Mid(protein, NextPosition, 0)
If NextLetter <> "P" Then
Dim PortionToCutOut = Mid(protein, 1, IndexPosition)
protein = Replace(protein, PortionToCutOut, "")
Console.WriteLine(PortionToCutOut)
End If
End If
Next index
Regex might be a simpler way to solve this:
Regex.Replace(protein, "^(.*?)[KR][^P]", "$1")
It means "from the start of the string, for zero or more captured characters up to the first occurrence of K or R followed by anything other than P, replace it with (the captured string)"
GLSDGEWQQVLNVWGKVEADIAGHGQEVLIRLFTGHPETL
^^^^^^^^^^^^^^^^^
captured string||
xx
Everything underlined with ^^^ is replaced by everything apart from the xx bit
It makes a single replacement, because that's what I interpreted you required when you said:
By using the replace function, if I replace a piece of string that then repeats later on, it removes the piece of string entirely from the long string instead of just the beginning
However if you do want to replace all occurrences of "K OR R followed by not P" it gets simpler:
Regex.Replace(protein, "[KR][^P]", "")
This is "K or R followed by anything other than P", replace with "nothing"
There are several issues with your code. The first issue that is likely to throw an exception is that you're modifying a collection in a For/Each loop.
The second issue that is less severe in immediate impact, but just as important in my opinion is that you're using almost exclusively legacy Visual Basic methods.
InStr should be replaced with IndexOf: https://learn.microsoft.com/en-us/dotnet/api/system.string.indexof
Mid should be replaced with Substring: https://learn.microsoft.com/en-us/dotnet/api/system.string.substring
The third issue is that you're not using the short-circuit operator OrElse in your conditional statement. Or will evaluate the right-hand side of your condition regardles of if the left-hand side is true whereas OrElse won't bother to evaluate the right-hand side if the left-hand side is true.
In terms of wanting to remove a piece of the String without using Replace, well you'd use Substring as well.
Consider this example:
Dim protein = "GLSDGEWQQVLNVWGKVEADIAGHGQEVLIRLFTGHPETLEKFDKFKHLKTEAEMKASEDLKKHGTVVLTALGGILKKKEGHHEAELKPLAQSHATKHKIPIKYLEFISDAIIHVLHSKHRPGDFGADAQGAMTKALELFRNDIAAKYKELGFQG"
Dim counter = 0
Do While counter < protein.Length - 2
counter += 1
Dim currentLetter = protein(counter)
Dim nextLetter = protein(counter + 1)
If (currentLetter = "K"c OrElse currentLetter = "R"c) AndAlso nextLetter <> "P"c Then
protein = protein.Substring(0, counter) & protein.Substring(counter + 1)
End If
Loop
Example: https://dotnetfiddle.net/vrhRdO

One line VBA statement expression with If-else condition

I am creating an VBA-like expression.
Replace([EmailAddress], "#domain.com", , , "", , )
[EmailAddress] is actually consist of a string, for example "john.doe#domain.com". So the result generated from the expression will be "john.doe"
I would like to set a condition where, if the result returned from the expression is more than 20 characters, the result return will be "john.d".
Basically remove all the characters behind the first character after the symbol "."
The idea is something like:
Variable a = Replace([EmailAddress], "#domain.com", , , "", , )
If len(a) > 20 then
an expression that remove all the characters after the symbol "." and first letter
else
a
End if
I am not sure if I am making sense, as I am not a programmer and not sure if these VBA syntax used are correct. I think there should be a single line expression to accommodate all these conditions.
Really appreciate if someone can help to guide me.
Below is a short VBA function that accepts an email address. If there is an "#" in there, it gets the text to the left of it. If this text is longer than 20 characters and has a "." in it, then get all of the text to the left of the ".", plus the "." and the next character.
Function fRemoveDomain(strDomain As String) As String
If InStr(strDomain, "#") > 0 Then
fRemoveDomain = Left(strDomain, InStr(strDomain, "#") - 1)
If (Len(fRemoveDomain) > 20) And (InStr(fRemoveDomain, ".") > 0) Then
fRemoveDomain = Left(fRemoveDomain, InStr(fRemoveDomain, ".") + 1)
End If
End If
End Function
Regards,
This UDF should do the trick assuming the input of your email always follows the format where everything in brackets can be a string that does not contain # or .:
[name].[name]#[domain].com
Public Function DOMAIN(Target As String) As String
If Len(Split(Target, "#")(0)) > 20 Then
Domain = Split(Target, ".")(0) & "." & Left(Split(Target, ".")(1), 1)
Else
Domain = Split(Target, "#")(0)
End If
End Function
You can call your UDF right on the worksheet like so:
Or from a macro like so:
You can also avoid using VBA altogether with
=IF(LEN(MID(A2,1,SEARCH("#",A2)-1))>20,MID(A2,1,FIND(".",A2)+1),MID(A2,1,SEARCH("#",A2)-1))

VB.Net Remove Multiple parentheses and text within from strings

So basically what I am trying to do in vb.net is remove multiple nested parentheses and all the text inside those parentheses from a string. It's easy to do if there is just one set of parentheses like in the first example below I just find the index of "(" and ")" and then use the str.remove(firstindex, lastindex) and just keep looping until all parentheses have been removed from the string.
str = "This (3) is(fasdf) an (asdas) Example"
Desired output:
str = "This is an example"
However I still can't figure out how to do it if their are multiple nested parentheses in the string.
str = "This ((dsd)sdasd) is ((sd)) an (((d))) an example"
Desired Outcome:
str = "This is an example"
This isn't really a tutorial site, so I shouldn't be answering this, but I couldn't resist.
As Ahmed said, you could use Regex.Replace, but I find Regexes complex and impenetrable. So it would be difficult for someone else to maintain it.
The following code has three loops. The our loop, a While loop, will run the two inner loops as long as the character index is less than the length of the string.
The first inner loop searches for the first "open bracket" in a group and records the position and adds 1 to the number of "open brackets" (the depth). Any subsequent "open brackets" just adds 1 to the number of brackets. This carries on until the first loop finds a "close bracket"
Then the second loop searches for the same number of "close brackets" from that point where the first "close bracket" is found.
When the loop gets to the last "close bracket" in the group, all the characters from the first "open bracket" to the last "close bracket" in the group are removed. Then the While loop starts again if the current index position is not at the end of the updated inputString.
When the While loop finishes, any double spaces are removed and the updated output string is returned from the function
Private Function RemoveBracketsAntContents(inputString As String) As String
Dim i As Integer
While i < inputString.Length
Dim bracketDepth As Integer = 0
Dim firstBracketIndex As Integer = 0
Do
If inputString(i) = "(" Then
If firstBracketIndex = 0 Then
firstBracketIndex = i
End If
bracketDepth += 1
End If
i += 1
Loop Until i = inputString.Length OrElse inputString(i) = ")"
If i = inputString.Length Then Exit While
Do
If inputString(i) = ")" Then
bracketDepth -= 1
End If
i += 1
Loop Until bracketDepth = 0
inputString = inputString.Remove(firstBracketIndex, i - firstBracketIndex)
i = i - (i - firstBracketIndex)
End While
inputString = inputString.Replace(" ", " ")
Return inputString
End Function

Compare two strings with wildcard

I want to compare two strings. I want to be able to say that s1 is equal to s2 because of the common word "hello". any suggestions on how to achieve this with or without another function?
s1: hello
s2: hello world
if s1 = s2 then
..do something
else
..do something
end if
It sounds as if you want to compare substrings, you can use String.Contains:
Dim s1 = "hello"
Dim s2 = "hello world"
Dim s2ContainsHello As Boolean = s2.Contains(s1) ' True
or (if you want to ignore the case) String.IndexOf which returns -1 if it wasn't found:
s2 = "Hello World"
s2ContainsHello = s2.IndexOf(s1, StringComparison.InvariantCultureIgnoreCase) >= 0 ' Still True
a third option in VB.NET is to use the Like operator (which also is case-sensitive by default):
s2ContainsHello = s2 like "*" & s1 & "*"
The Like-operator supports wild-cards:
Characters in pattern Matches in string
? Any single character
* Zero or more characters
# Any single digit (0–9)
[charlist] Any single character in charlist
[!charlist] Any single character not in charlist
If you're just looking for whether or not both strings have "hello" somewhere in them
If s1.Contains("hello") AndAlso s2.Contains("hello") Then
'do something
Else
'do something else
End If