Given the following string...
鉴于以下字符串......
"localhost:9000/one/two/three"
I want to truncate it after the word two
and get
我想在单词二之后截断它并得到
"localhost:9000/one/two"
I've implemented the methods truncateBefore
and truncateAfter
like this:
我已经实现了truncateBefore和truncateAfter方法,如下所示:
def truncateBefore(s: String, p: String) = {
s.substring(s.indexOf(p) + p.length, s.length)
}
def truncateAfter(s: String, p: String) = {
s.substring(0, s.indexOf(p) + p.length)
}
These methods work and return the expected results:
这些方法起作用并返回预期结果:
scala> truncateAfter("localhost:9000/one/two/three", "three")
res1: String = localhost:9000/one/two
scala> truncateBefore("localhost:9000/one/two/three", "three")
res2: String = /three
Is there a better way to do this in scala? Preferably with a regex?
在scala中有更好的方法吗?最好用正则表达式?
4 个解决方案
#1
2
Splitting after the first literal, without much regex-fu (pun intended).
在第一个字面之后拆分,没有太多正则表达式(双关语)。
scala> implicit class `split after`(val s: String) {
| def splitAfter(p: String): (String, String) = {
| val r = (Regex quote p).r
| r findFirstMatchIn s map (m => (s.substring(0, m.end), m.after.toString)) getOrElse (s, "")
| }}
defined class split$u0020after
scala> "abcfoodeffooghi" splitAfter "foo"
res2: (String, String) = (abcfoo,deffooghi)
scala> "abc*def" splitAfter "*"
res3: (String, String) = (abc*,def)
#2
5
One option using regex:
使用正则表达式的一个选项:
val beforeAfter = "(^.*two)(.*)$".r
scala> val beforeAfter(after, before) = "localhost:9000/one/two/three"
after: String = localhost:9000/one/two
before: String = /three
Another option using split:
使用split的另一种选择:
scala> "localhost:9000/one/two/three" split ("two")
res0: Array[java.lang.String] = Array(localhost:9000/one/, /three)
These are not super robust solutions in case you don't have a word two
in the input, but you can handle it accordingly...
如果您在输入中没有单词2,这些不是超级强大的解决方案,但您可以相应地处理它...
One more using regex in for comprehension:
再使用正则表达式进行理解:
scala> val beforeAfter = "(^.*two)(.*)$".r
beforeAfter: scala.util.matching.Regex = (^.*two)(.*)$
scala> (for {
| matches <- beforeAfter.findAllIn("localhost:9000/one/two/three").matchData
| tokens <- matches.subgroups
| } yield tokens).toList
res0: List[String] = List(localhost:9000/one/two, /three)
which is safe if no matches found:
如果找不到匹配项,这是安全的:
scala> (for {
| match <- beforeAfter.findAllIn("localhost").matchData
| token <- match.subgroups
| } yield token).toList
res1: List[String] = List()
#3
1
Obviously not efficient, but it works.
显然效率不高,但有效。
scala> val url = "localhost:9000/one/two/three"
url: String = localhost:9000/one/two/three
scala> url.reverse.dropWhile(_ != '/').reverse
res0: String = localhost:9000/one/two/
With an index:
带索引:
scala> url.drop(url.reverse.indexOf('/'))
res1: String = host:9000/one/two/three
#4
1
OK, thanks to everybody... and here is my solution:
好的,感谢大家......这是我的解决方案:
package object typeExtensions {
implicit class StringExtensions(val string: String) extends AnyVal {
def truncateAfter(pattern: String) = beforeAfter(pattern).map(_._1).getOrElse(string)
def truncateBefore(pattern: String) = beforeAfter(pattern).map(_._2).getOrElse(string)
private def beforeAfter(pattern: String) = {
if (string.contains(pattern)) {
val beforeAfter = ("(^.*" + Pattern.quote(pattern) + ")(.*)$").r
val beforeAfter(before, after) = string
Some(before, after)
} else None
}
}
}
Any suggestion to improve the code above is more than welcome ;-)
任何改进上述代码的建议都非常受欢迎;-)
#1
2
Splitting after the first literal, without much regex-fu (pun intended).
在第一个字面之后拆分,没有太多正则表达式(双关语)。
scala> implicit class `split after`(val s: String) {
| def splitAfter(p: String): (String, String) = {
| val r = (Regex quote p).r
| r findFirstMatchIn s map (m => (s.substring(0, m.end), m.after.toString)) getOrElse (s, "")
| }}
defined class split$u0020after
scala> "abcfoodeffooghi" splitAfter "foo"
res2: (String, String) = (abcfoo,deffooghi)
scala> "abc*def" splitAfter "*"
res3: (String, String) = (abc*,def)
#2
5
One option using regex:
使用正则表达式的一个选项:
val beforeAfter = "(^.*two)(.*)$".r
scala> val beforeAfter(after, before) = "localhost:9000/one/two/three"
after: String = localhost:9000/one/two
before: String = /three
Another option using split:
使用split的另一种选择:
scala> "localhost:9000/one/two/three" split ("two")
res0: Array[java.lang.String] = Array(localhost:9000/one/, /three)
These are not super robust solutions in case you don't have a word two
in the input, but you can handle it accordingly...
如果您在输入中没有单词2,这些不是超级强大的解决方案,但您可以相应地处理它...
One more using regex in for comprehension:
再使用正则表达式进行理解:
scala> val beforeAfter = "(^.*two)(.*)$".r
beforeAfter: scala.util.matching.Regex = (^.*two)(.*)$
scala> (for {
| matches <- beforeAfter.findAllIn("localhost:9000/one/two/three").matchData
| tokens <- matches.subgroups
| } yield tokens).toList
res0: List[String] = List(localhost:9000/one/two, /three)
which is safe if no matches found:
如果找不到匹配项,这是安全的:
scala> (for {
| match <- beforeAfter.findAllIn("localhost").matchData
| token <- match.subgroups
| } yield token).toList
res1: List[String] = List()
#3
1
Obviously not efficient, but it works.
显然效率不高,但有效。
scala> val url = "localhost:9000/one/two/three"
url: String = localhost:9000/one/two/three
scala> url.reverse.dropWhile(_ != '/').reverse
res0: String = localhost:9000/one/two/
With an index:
带索引:
scala> url.drop(url.reverse.indexOf('/'))
res1: String = host:9000/one/two/three
#4
1
OK, thanks to everybody... and here is my solution:
好的,感谢大家......这是我的解决方案:
package object typeExtensions {
implicit class StringExtensions(val string: String) extends AnyVal {
def truncateAfter(pattern: String) = beforeAfter(pattern).map(_._1).getOrElse(string)
def truncateBefore(pattern: String) = beforeAfter(pattern).map(_._2).getOrElse(string)
private def beforeAfter(pattern: String) = {
if (string.contains(pattern)) {
val beforeAfter = ("(^.*" + Pattern.quote(pattern) + ")(.*)$").r
val beforeAfter(before, after) = string
Some(before, after)
} else None
}
}
}
Any suggestion to improve the code above is more than welcome ;-)
任何改进上述代码的建议都非常受欢迎;-)