I want to Validate the list of Email which is comma Separated in Scala.
For Ex:1) a#gmail.com,b#gmail.com,c#gmail.com ---Valid
2) a#gmail.com,b##gmail.com,c#gmail.com---Invalid
3) a#gmail.com,b#gmail.com.c#gmail.com----Invalid
Depending on what "invalid" means, this could work:
def isValid(emails: String): Boolean = {
return emails.split(",").map(_.count(_ == '#') == 1).reduce(_ && _)
}
isValid("a#gmail.com,b#gmail.com,c#gmail.com") // true
isValid("a#gmail.com,b##gmail.com,c#gmail.com") // false
isValid("a#gmail.com,b#gmail.com.c#gmail.com") // false
I'm just splitting the string by commas, then I check that there is only one # in it.
If you really want to check that the email is correct, you can use a regex like this:
def isValid(emails: String): Boolean = {
return emails.split(",").map(_.matches(raw"[\w-\.]+#([\w-]+\.)+[\w-]{2,4}")).reduce(_ && _)
}
This is probably better, but it is not specific enough to capture all email specificities. Matching all types of emails is not something easy to do with regex (see this question).
Related
Starting with Scala. I am trying to code this:
def getPortNamePart(portName: String) {
val maybePortName = portName.filter(_.trim.length > 0)
val portNamePart = maybePortName.map(portName => s"_$portName").getOrElse("")
}
println(getPortNamePart("something")) // expected "something"
println(getPortNamePart("")) // expected ""
println(getPortNamePart(" ")) // expected ""
But I get:
:10: error: value trim is not a member of Char
val maybePortName = portName.filter(_.trim.length > 0)
Which tells me that the filter is being applied to the each character of the string.
But I do not want that, I want the filter to be applied to the string. How can I code my filtering so that it happens at the string level?
If I understood correctly what you want to achieve:
def getPortNamePart(portName: String) =
Option(portName).filter(_.trim.length > 0).map(portName => s"_$portName").getOrElse("")
filter works on exactly the same collection you applied it to (and String can be thought of as a collection of chars). So if you want to get Option on String filtering, you need to wrap it with Option first.
That's how filter works over strings. What you want is:
if(portName.trim.length>0) portName else ""
For this simple case you don't need any functional constructs. Do it with simple if .. else statements
What is the right way to validate an input value in Scala ? Suppose I have a password to validate with the following rules
Password should not be empty
Password length should be greater than 8 characters
There can be more validation rules. But the goal is run all the rules and return a list of Errors (List[String]).
The following are the two ways I can think of. But is there a better way?
The code
import scala.collection.mutable.ListBuffer
//Validate password using mutable list (Feels like Java style coding)
//Uses mutable list but seems a bit simpler
def validatePasswordMutableList(password: String): List[String] = {
val errors = ListBuffer.empty[String]
if (password == "")
errors += "Is empty."
if (password.length < 8)
errors += "Not long enough."
errors.toList
}
validatePasswordMutableList("") foreach println
//Validate password using Immutable list
//But has to run filter and map on the error list to get desired result.
def validatePasswordImmutableList(password: String): List[String] = {
def isEmpty = if (password == "") Some("Is empty.") else None
def isLengthValid = if (password.length < 8) Some("Not long enough.") else None
val errors = isEmpty :: isLengthValid :: Nil
errors.filter(_.isDefined).map(_.get)
}
validatePasswordImmutableList("") foreach println
One approach you should consider is to process an unlimited select of dynamic rules, passed as a list (or sequence) of functions. This way, you can recycle some or all of those rules and easily update new ones in the future.
It would be much simpler to use functions that just return Boolean, however the code below has the advantage of returning all password violations that happened in a similar way most website and applications do these days.
object ValidateExample extends App {
def applyFilters(password:String, rules:Seq[Function[String,Option[String]]]):Seq[String] = {
//You could use a while loop here if you had many rules, and wanted to stop early
val temp = rules.flatMap{f=> f(password) } //seq of items that converted to Some(string) only
temp
}
val rule1:(String)=>Option[String] = { s=>
if (s.length<8) Some("Error in password length") else None
}
//same idea different declaration syntax
val rule2:Function[String,Option[String]] = { s=>
if (s.contains("X")) Some("Error cant contain capitol X") else None
}
//example of a partial function, lifted below
val rule3:PartialFunction[String,String]={case s:String if s.isEmpty =>"Password can't be empty"}
val test1 = applyFilters("helloX",Seq(rule1,rule2,rule3.lift))
println(test1)
val test2 = applyFilters("",Seq(rule1,rule3.lift))
println(test2)
//example passed
val passed = test2.isEmpty
}
Output:
List(Error in password length, Error cant contain capitol X)
List(Error in password length, Password can't be empty)
I have a string, lets say val mystr = "abcde", and I want to find the minimal substring of mystr which satisfies a given condition. I have to send a string to an external system, so the only way to do this is to iterate through the length of the string and make requests to the external system, and break when the response from the external system returns true
eg.
callExtSystemWith("a") //Returns false
callExtSystemWith("ab") //Returns false
callExtSystemWith("abc") //Returns true
Then my method should return "abc". I read that breaks are not the scala way, so was wondering what is the scala way of achieving this?
Right now I have:
for {end <- 1 to mystr.length)}{
callExtSystemWith(mystr.substring(0,end))
// I Want to break when this is true.
}
Help much appreciated
You can use inits.toStream.reverse.drop(1) (1 to s.length).map(s.take).toStream to create a lazy stream with a, ab, abc, abcd.
Then filter those strings, so that only the ones for which callExtSystemWith returns true are left.
Then get the first string for which callExtSystemWith returns true. Because this is a lazy stream, no unecessary requests will be made to the server once the first match is found.
val s = "abcdefgh"
val strs = (1 to s.length).map(s.take).toStream
strs.filter(callExtSystemWith).headOption match {
case Some(s) => "found"
case _ => "not found"
}
You can also use find instead of filter + headOption
Quite often break can be replaced with find on some sequence
So here is another short solution for this problem:
def findSuitablePrefix(mystr: String): Option[String] =
(1 to mystr.length).view.map(mystr.substring(0, _)).find(callExtSystemWith)
.view makes the evaluation lazy to avoid creating extra substrings.
.map transforms the sequence of indexes into a sequence of substrings.
And .find "breaks" after the first element for which callExtSystemWith returns true is found.
In Scala there are no normal breaks but there are other solutions. The one I like better is to create a function and force a return (instead of a normal break). Something like:
def callAndBreak(mystr:String) : Int = {
for (end <- 1 to mystr.length) {
if ( callExtSystemWith(mystr.substring(0,end)) ) return end
}
end
}
Here I return end but you can return anything
If you want to avoid using return or breaks, you could also use foldLeft:
val finalResult = (1 to mystr.length).foldLeft(false) { (result, end) =>
if(!result) callExtSystemWith(mystr.substring(0, end)) else result
}
However, it is a bit hard to read, and will walk the entire length of the string.
Simple recursion might be a better way:
def go(s: String, end: Int): Boolean = {
if(end >= s.length) false
else {
callExtSystemWith(s.substring(0, end)) || go(s, end + 1)
}
}
go(mystr, 1)
Yesterday I was suddenly enlighted and understood how and why people use 'map' method with Option to compare values. Yes, I'm a bit slow, sorry :)
I revised these very nice links and came to the question I would like to ask.
http://twitter.github.com/effectivescala
http://blog.tmorris.net/posts/scalaoption-cheat-sheet
In my Lift webapp I have some Option[User] and Option[Server] variables. I'm trying to find out if this User is admin of this Server by the following check
if(user.map(_.id) == server.map(_.adminId))
But I noticed that in case of 'user' is None and 'server' is also None this check succeeds which is not good for me (if any of them is None I'd like this check to fail). I could add user.isDefined condition but I feel there is more correct way to do it. Could you tell how to accomplish it in Scala way?
You could do it with pattern matching (which in this case is probably the clearest way):
(user, server) match {
case (Some(user), Some(server)) if user.id == server.adminId =>
// both ids are matching, handle this case here
case _ =>
// no match, handle this case here
}
You could also try as a one-liner but here I don't advise it as it's pretty obfuscated:
if ( user.flatMap{ user => server.map(_.adminId == user.id) }.getOrElse( false ) ) {
// both ids are matching, handle this case here
}
else {
// no match, handle this case here
}
Finally, if you only have to handle the case where the ids match (and would just do nothing if there is not), using a for comprehension is not too bad of an option (no pun intended):
for ( user <- user; server <- server if user.id == server.adminId ) {
// both ids are matching, handle this case here
}
I got used to the combination of exists / contains for this purpose.
When comparing two options of the same type:
o1.exists(o2.contains)
In your case this can be applied using map:
user.map(_.id).exists(server.map(_.adminId).contains)
you can use a for comprehension
def isAdmin(server: Option[Server])(user: Option[User]): Boolean = (for {
s <- server
u <- user
} yield (u.id == s.adminId)
).getOrElse(false)
The comprehension results in a Option[Boolean] from which you get the value or false if there's no value (the case where any of the options is None, as you requested)
Why curried?
I made the method curried, so you can define you function for a specific server, and then reuse that to check many users
def isMyServerAdmin = isAdmin(Some(myServer)) _
isMyServerAdmin(Some(user1)) = true
isMyServerAdmin(Some(user2)) = false
isMyServerAdmin(None) = false
We can make use of Option#zip to work with an Option of the tuple user/server:
user zip server exists { case (user, server) => user.id == server.adminId }
where the behavior of Option#zip is:
Some(User(id = "hello")) zip Some(Server(adminId = "world"))
// Some((User("hello"), Server("world")))
Some(User(id = "hello")) zip None // None
None zip Some(Server(adminId = "world")) // None
None zip None // None
and where Option#exists applies a predicate on the optional tuple produced by zip.
Given a list of word pairs
val terms = ("word1a", "word1b") :: ("word2a", "word2b") :: ... :: Nil
What's the most elegant way in Scala to test if at least one of the pairs occur in a text? The test should terminate as quick as possible when it hits the first match. How would you solve that?
EDIT: To be more precise I want to know if both words of a pair appear somewhere (not necessarily in order) in the text. If that's the case for one of the pairs in the list the method should return true. It's not necessary that the matched pair is returned, neither it's important if more than one pair matches.
scala> val text = Set("blah1", "word2b", "blah2", "word2a")
text: scala.collection.immutable.Set[java.lang.String] = Set(blah1, word2b, blah2)
scala> terms.exists{case (a,b) => text(a) && text(b)}
res12: Boolean = true
EDIT: Note that using a set to represent the tokens in the text makes the lookup from the contains much more efficient. You wouldn't want to use something sequential like a List for that.
EDIT 2: Updated for clarification in requirement!
EDIT 3: changed contains to apply per the suggestion in the comment
EDIT - seems like the ambiguous wording of your question means I answered a different question:
Because you are essentially asking for either of the pair; you might as well flatten all these into one big set.
val words = (Set.empty[String] /: terms) { case (s, (w1, w2)) => s + w1 + w2 }
Then you are just asking whether any of these exist in the text:
text.split("\\s") exists words
This is fast because we can use the structure of a Set to lookup quickly whether the word is contained in the text; it terminates early due to the "exists":
scala> val text = "blah1 blah2 word2b"
text: java.lang.String = blah1 blah2 word2b
In the case that your text is very long, you may wish to Stream it, so that the next word to test is lazily computed, rather than split the String into substrings up-front:
scala> val Word = """\s*(.*)""".r
Word: scala.util.matching.Regex = \s*(.*)
scala> def strmWds(text : String) : Stream[String] = text match {
| case Word(nxt) => val (word, rest) = nxt span (_ != ' '); word #:: strmWds(rest)
| case _ => Stream.empty
| }
strmWds: (text: String)Stream[String]
Now you can:
scala> strmWds(text) exists words
res4: Boolean = true
scala> text.split("\\s") exists words
res3: Boolean = true
I'm assuming that both elements of the pair have to appear in the text, but it doesn't matter where, and it doesn't matter which pair appears.
I'm not sure this is the most elegant, but it's not bad, and it's fairly fast if you expect that the text probably has the words (and thus you don't need to read all of it), and if you can generate an iterator that will give you the words one at a time:
case class WordPair(one: String, two: String) {
private[this] var found_one, found_two = false
def check(s: String): Boolean = {
if (s==one) found_one = true
if (s==two) found_two == true
found_one && found_two
}
def reset {
found_one = false
found_two = false
}
}
val wordpairlist = terms.map { case (w1,w2) => WordPair(w1,w2) }
// May need to wordpairlist.foreach(_.reset) first, if you do this on multiple texts
text.iterator.exists(w => wordpairlist.exists(_.check(w)))
You could further improve things by putting all the terms in a set, and not even bothering to check the wordpairlist unless the word from the text was in that set.
If you mean that the words have to occur next to each other in order, you then should change check to
def check(s: String) = {
if (found_one && s==two) found_two = true
else if (s==one) { found_one = true; found_two = false }
else found_two = false
found_one && found_two
}