34

I have an Option[String].

I want to check if there is a string exists and if it's exists its not blank.

def isBlank( input : Option[String]) : Boolean = 
{ 
     input.isEmpty || 
     input.filter(_.trim.length > 0).isEmpty 
}

Is there is a better way of doing this in Scala ?

Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
Soumya Simanta
  • 11,523
  • 24
  • 106
  • 161

9 Answers9

75

What you should do is check using exists. Like so:

myOption.exists(_.trim.nonEmpty)

which will return True if and only if the Option[String] is not None and not empty.

wheaties
  • 35,646
  • 15
  • 94
  • 131
  • this is not correct : scala> val myOption: Option[String] = None myOption: Option[String] = None scala> myOption.exists(_.trim.nonEmpty) res1: Boolean = false – Maxim Mar 12 '15 at 22:03
  • 1
    As I understand he want it to be True on None. I like your short code, but it's exactly the inverse. Should be - myOption.forall(_.trim.isEmpty) – Maxim Mar 12 '15 at 22:12
  • That also works. I avoid using forall in example code here due to the non-obvious implications on None. – wheaties Mar 12 '15 at 22:16
  • This fails with null value. Any ideas how to set it up with possible null as well? – Kapil Malhotra Jun 14 '17 at 03:19
  • @KapilMalhotra if you have a `Some(null)` you're doing `Option` wrong. The `Option` constructor will automatically convert to a `None` if you use it. If, instead, you're passing a value into the `Some` constructor, you lose that safety guarantee. – wheaties Jun 14 '17 at 13:53
6

An approach based in pattern matching,

def isBlank( input : Option[String]) : Boolean = 
  input match {
    case None    => true
    case Some(s) => s.trim.isEmpty
  }
elm
  • 20,117
  • 14
  • 67
  • 113
5

exists (Accepted solution) will work when input has at least one element in it, that is Some("") but not when it's None.

exists checks if at least one element(x) applies to function.

eg.

scala> List[String]("apple", "").exists(_.isEmpty)
res21: Boolean = true

//if theres no element then obviously returns false
scala> List[String]().exists(_.isEmpty)
res30: Boolean = false

Same happens with Option.empty, as theres no element in it,

scala> Option.empty[String].exists(_.isEmpty)
res33: Boolean = false

So forall is what makes sure the the function applies all the elements.

scala> def isEmpty(sOpt: Option[String]) = sOpt.forall(_.trim.isEmpty)
isEmpty: (sOpt: Option[String])Boolean

scala> isEmpty(Some(""))
res10: Boolean = true

scala> isEmpty(Some("non-empty"))
res11: Boolean = false

scala> isEmpty(Option(null))
res12: Boolean = true

The gross way is to filter nonEmpty string, then check option.isEmpty.

scala> def isEmpty(sOpt: Option[String]) = sOpt.filter(_.trim.nonEmpty).isEmpty
isEmpty: (sOpt: Option[String])Boolean

scala> isEmpty(None)
res20: Boolean = true

scala> isEmpty(Some(""))
res21: Boolean = true
prayagupa
  • 30,204
  • 14
  • 155
  • 192
3

This should work as well since filter of an empty Option results in an empty Option

def isBlank( input : Option[String]) : Boolean =  
   input.filter(_.trim.length > 0).isEmpty 
Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
2

All proposed solutions will crash with NullPointerException if you pass:

val str : Option[String] = Some(null). 

Therefore null-check is a must:

def isBlank(input: Option[String]): Boolean = 
  input.filterNot(s => s == null || s.trim.isEmpty).isEmpty
karol.bu
  • 21
  • 1
  • 3
    But you should never be passing `Some(null)`. It destroys the benefit of using `Option`! – Robin Green Apr 05 '15 at 09:49
  • 1
    It is public method and you never know, how someone might misbehave with your provided contract. Therefore, I think, it is always good to double check and not to step on nullPointer. – karol.bu Apr 20 '15 at 21:31
1

I am from C# background and found Scala implicit methods similar to C# extensions

import com.foo.bar.utils.MyExtensions._
...

"my string".isNullOrEmpty  // false
"".isNullOrEmpty           // true
" ".isNullOrEmpty          // true
"  ".isNullOrEmpty         // true

val str: String  = null
str.isNullOrEmpty          // true

Implementation

package com.foo.bar.utils

object MyExtensions {

  class StringEx(val input: String) extends AnyVal {

    def isNullOrEmpty: Boolean =    
      if (input == null || input.trim.isEmpty)
        true
      else
        false
  }

  implicit def isNullOrEmpty(input: String): StringEx = new StringEx(input)
}
oleksii
  • 35,458
  • 16
  • 93
  • 163
  • you can use implicit class btw: implicit class StringExtensions(val input: String) { def isNullOrEmpty: Boolean = input == null || input.trim.isEmpty } – EvgeniyK Apr 27 '16 at 04:49
1

I added a Scalafiddle to play with that: Scalafiddle

That shows the marked correct answer is wrong (as pointed out by prayagupd):

def isBlank(str: Option[String]): Boolean =
   str.forall(_.trim.isEmpty)

the solution is for non-blank:

def isNotBlank(str: Option[String]): Boolean =
   str.exists(_.trim.nonEmpty)   
pme
  • 14,156
  • 3
  • 52
  • 95
1

You can also take advantage of Extractor pattern. It makes codes much more declarative.

For example:

object NonBlank {
  def unapply(s: String): Option[String] = Option(s).filter(_.trim.nonEmpty) 
}

And then use it like

def createUser(name: String): Either[Error, User] = name match {
  case NonBlank(username) => Right(userService.create(username))
  case _ => Left(new Error("Invalid username. Blank usernames are not allowed."))
}
Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96
-1

you can also check using lastOption or headOption

if the string is empty it will return None

scala> "hello".lastOption
res39: Option[Char] = Some(o)

scala> "".lastOption
res40: Option[Char] = None
Hackaholic
  • 19,069
  • 5
  • 54
  • 72
  • This addresses a `String` and not an `Option[String]` as requested. Also, an empty string, `""`, is not the same as a "blank" string (i.e. whitespace). – jwvh Jan 21 '20 at 00:45
  • scala> " ".lastOption val res20: Option[Char] = Some( ) sorry that's not going to work – shinzou Jul 20 '21 at 09:33