find by regular expression with Casbah - scala

how to use regular expressions at Collection#find(/* HERE */) like:
val coll = MongoConnection()("foo")("bar")
for(x <- coll.find("name" -> ".*son$".r)) {
// some operations...
}

You are close, you just need to wrap your conditions in a MongoDBObject().
We had to pull out the implicit conversions of <key> -> <value> in a bunch of places because they were hard to catch properly and were breaking other code.
They'll probably be back in 2.1.
Do this instead:
val coll = MongoConnection()("foo")("bar")
for(x <- coll.find(MongoDBObject("name" -> ".*son$".r))) {
// some operations...
}

For adding IGNORECASE above answer will not work by appending "/i" at the end of regex in Scala, Casbah.
For this purpose use:
val EmailPattern = Pattern.compile(companyName,Pattern.CASE_INSENSITIVE)
val q = MongoDBObject("companyName" -> EmailPattern)
val result = MongoFactory.COLLECTION_NAME.findOne(q)

Related

List to multiple anonymous/underscore parameters in for-comprehension

I'm kind of new to Scala/functional so I'm not yet able to use technical language.
I'm experiencing problems with a for-comprehension
val queries =
for {
_ <- createBanco
_ <- createBancoMedio
bankInsertions <- Update[Banco](insertStr).updateMany(NonEmptyList.fromList(createBankList(1, maxBanks)).get)
mediumInsertions <- Update[BancoMedio](mediumInsert).updateMany(NonEmptyList.fromList(mediumList).get)
bankCount <- BancoStatements.getCount().unique
bankGetIds <- BancoStatements.getIds(0, maxBanks).to[List]
bankSome <- BancoStatements.getSome(halfBanks).to[List]
} yield (bankCount, bankGetIds, bankSome)
//Execute database queries, saves them on tuple
val transactionResults : (Int, List[String], List[Banco]) =
queries.transact(h2Transactor).unsafeRunSync()
I'm trying to refactor the _ <- createBanco & _ <- createBancoMedio, which are both a ConnectionIO[Int] object.
Id like to convert those to a single List(createBanco, createBancoMedio) and then execute transact.
However, i'd be altering the return type of the for-comprehension by doing that. I'd like to know if there is any way on doing that without affecting the for output value
Basically, treat the list as if I was writing multiple anonymous parameters manually.
You can use .sequence to turn a List[G[A]] into a G[List[A]] if G has an Applicative instance, which ConnectionIO does:
val queries =
for {
_ <- List(createBanco, createBancoMedio).sequence
...
Just solved it, did another for comprehension for the List
val createList = for {
m <- createBancoMedio
b <- createBanco
} yield List(b, m)
val queries =
for {
_ <- createList ....
This way i had a ConnectionIO[List[Int]]

What is the equivalent of F# seq monad in Scala

I'm trying to move from F# to Scala. In F#, we can easily create a seq with computation expression or monad. For example:
let myseq = seq {
let mutableList = List()
for i = 0 to 100 do
mutableList.append(i)
yield sum(mutableList)
}
myseq |> Seq.iter println
I read about scala Stream, but I'm not for sure how to use it properly, like the above example, which contains some state keep updating during the seq generation.
Another example would be to do some initialization and cleanup job inside the seq:
let myseq = seq {
let file = open(path)
while (x = read(file)) do
yield x
file.close() }
Can we do this in scala?
Scala has Sequence Comprehensions using the for and yield keywords, as in the following example:
object ComprehensionTest extends App {
def even(from: Int, to: Int): List[Int] =
for (i <- List.range(from, to) if i % 2 == 0) yield i
Console.println(even(0, 20))
}

Parse nginx rewrite rules to extract from and to

If I have, say, a list of nginx-esque config rewrite statement as such:
val rewritesList : List[String] = List(
"rewrite (?i)^/first$ http://www.firstredirect.com redirect;",
"rewrite (?i)^/second$ http://www.seconredirect.com redirect;"
)
And I would like to extract from and to from that list. I am not worried about the final structure as long as I extract the info, but for sake of demonstration:
val rewritesMap : Map[String, String] = Map(
"first" -> "http://www.firstredirect.com",
"second" -> "http://www.seconredirect.com"
)
You can use regular expressions with Scala's pattern matching:
val rewritesList : List[String] = List(
"rewrite (?i)^/first$ http://www.firstredirect.com redirect;",
"rewrite (?i)^/second$ http://www.seconredirect.com redirect;"
)
val Regex = """^rewrite \(\?i\)\^/(\w+)\$ ([^ ]+) redirect;$""".r
val rewritesMap = (for {
Regex(from, to) <- rewritesList
} yield (from -> to)).toMap
println(rewritesMap)
You could also use the more explicit findFirstMatchIn to extract a single match:
val rewritesMap = (for {
str <- rewritesList
} yield {
val m = Regex.findFirstMatchIn(str).get
(m.group(1), m.group(2))
}).toMap
Both versions print (up to indentation):
Map(
first -> http://www.firstredirect.com,
second -> http://www.seconredirect.com
)
Note that the latter variant will throw a NoSuchElementException if the input data is not of the format defined by the regex. I don't know what you want to do if the data does not match the regex: you can raise exceptions, but you can also simply skip the cases that aren't parsed correctly.

What is a more Scala way of writing this code?

I want to strip off the word "America/" from the start of each item in the list, and the code below does just that, but I feel like it can be done in a significantly better way.
var tz = java.util.TimeZone.getAvailableIDs
for(i <- 0 until tz.length) {
if(tz(i).startsWith("America/")) {
tz(i) = tz(i).replaceFirst("America/", "")
}
}
Simple and straight forward:
val tz = java.util.TimeZone.getAvailableIDs.map(_.replaceFirst("^America/", ""))
very similar to #Noah's answer, but using a for-yield iteration (so that you can add other filters with no more usage of parentheses).
import java.util.TimeZone
val tz = for(t <- TimeZone.getAvailableIDs) yield t.replaceFirst("^America/", "")
I will use regex for it:
val pattern = "^America/".r
tz = tz.map(pattern.replaceFirstIn(_, ""))
wonder if it is an effcient way.
Map is preferred to for loops in functional programming, so instead of changing the list in place with a for loop, passing the data around by mapping is more pure and (IMO) prettier.
this can work:
val tzs = java.util.TimeZone.getAvailableIDs map { tz =>
if(tz.startsWith("America/")) tz.replaceFirst("America/","")
else tz
}
If you only want the American time zones, you could do this:
val americanZones = {
val pattern = "^America/(.*)".r
( java.util.TimeZone.getAvailableIDs
flatMap pattern.findFirstMatchIn
map (_ group 1) )
}
Added an 'if' to the for/yield
val zones = java.util.TimeZone.getAvailableIDs
val formatted_zones = for(i <- 0 until zones.length if zones(i).startsWith("America/")) yield {
zones(i).replaceFirst("America/", "")
}
No regex:
val tz = java.util.TimeZone.getAvailableIDs.map(_ stripPrefix "America/")

How should I match a pattern in Scala?

I need to do a pattern in Scala, this is a code:
object Wykonaj{
val doctype = DocType("html", PublicID("-//W3C//DTD XHTML 1.0 Strict//EN","http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"), Nil)
def main(args: Array[String]) {
val theUrl = "http://axv.pl/rss/waluty.php"
val xmlString = Source.fromURL(new URL(theUrl)).mkString
val xml = XML.loadString(xmlString)
val zawartosc= (xml \\ "description")
val pattern="""<descrition> </descrition>""".r
for(a <-zawartosc) yield a match{
case pattern=>println(pattern)
}
}
}
The problem is, I need to do val pattern=any pattern, to get from
<description><![CDATA[ <img src="http://youbookmarks.com/waluty/pic/waluty/AUD.gif"> dolar australijski 1AUD | 2,7778 | 210/A/NBP/2010 ]]> </description>
only it dolar australijski 1AUD | 2,7778 | 210/A/NBP/2010.
Try
import scala.util.matching.Regex
//...
val Pattern = new Regex(""".*; ([^<]*) </description>""")
//...
for(a <-zawartosc) yield a match {
case Pattern(p) => println(p)
}
It's a bit of a kludge (I don't use REs with Scala very often), but it seems to work. The CDATA is stringified as > entities, so the RE tries to find text after a semicolon and before a closing description tag.
val zawartosc = (xml \\ "description")
val pattern = """.*(dolar australijski.*)""".r
val allMatches = (for (a <- zawartosc; text = a.text) yield {text}) collect {
case pattern(value) => value }
val result = allMatches.headOption // or .head
This is mostly a matter of using the right regular expression. In this case you want to match the string that contains dolar australijski. It has to allow for extra characters before dolar. So use .*. Then use the parens to mark the start and end of what you need. Refer to the Java api for the full doc.
With respect to the for comprehension, I convert the XML element into text before doing the match and then collect the ones that match the pattern by using the collect method. Then the desired result should be the first and only element.