স্কালায় নিয়মিত এক্সপ্রেশন ব্যবহার করে কীভাবে প্যাটার্ন মিলবে?


124

আমি শব্দের প্রথম অক্ষর এবং "এবিসি" এর মতো একটি গ্রুপের একটি অক্ষরের মধ্যে একটি মিল খুঁজে পেতে চাই। সিউডোকোডে, এটি দেখতে কিছুটা দেখতে পাবেন:

case Process(word) =>
   word.firstLetter match {
      case([a-c][A-C]) =>
      case _ =>
   }
}

তবে আমি জাভা পরিবর্তে স্ক্যালায় প্রথম চিঠিটি কীভাবে ধরব? আমি কীভাবে নিয়মিত প্রকাশটি সঠিকভাবে প্রকাশ করব? কেস ক্লাসের মধ্যে এটি করা সম্ভব ?


9
সতর্কতা অবলম্বন করুন: স্কালায় (এবং * এমএল ভাষাগুলি), প্যাটার্ন মিলের আরেকটি রয়েছে, রেজেক্সেস থেকে অর্থ আলাদা very

1
আপনি সম্ভবত [a-cA-C]নিয়মিত প্রকাশের জন্য চান ।

2
স্কেল ২.৮-এ, স্ট্রিংগুলিকে Traversable(লাইক Listএবং Array) তে রূপান্তর করা হয় , যদি আপনি প্রথম 3 টি অক্ষর চান তবে প্রথমটির "my string".take(3)জন্য চেষ্টা করুন"foo".head
শেলহোলিক

উত্তর:


237

আপনি এটি করতে পারেন কারণ নিয়মিত এক্সপ্রেশনগুলি এক্সট্র্যাক্টরগুলি সংজ্ঞায়িত করে তবে আপনাকে প্রথমে রেজেক্স প্যাটার্নটি সংজ্ঞায়িত করতে হবে। এটি পরীক্ষা করার জন্য আমার কাছে কোনও স্কেলা রিপাবল অ্যাক্সেস নেই তবে এর মতো কিছু কাজ করা উচিত।

val Pattern = "([a-cA-C])".r
word.firstLetter match {
   case Pattern(c) => c bound to capture group here
   case _ =>
}

5
সাবধান হন যে আপনি কোনও ক্যাপচার গ্রুপ ঘোষণা করতে পারবেন না এবং তারপরে এটি ব্যবহার করবেন না (যেমন কেস প্যাটার্ন () এখানে মেলে না)
জেরেমি লাইপজিগ

34
সতর্ক থাকুন যে আপনার উচিত নয় আপনার নিয়মিত এক্সপ্রেশনে গ্রুপ ব্যবহার করুন: val Pattern = "[a-cA-C]".rকাজ করবে না। এটি কারণ ম্যাচ-কেস ব্যবহার করে unapplySeq(target: Any): Option[List[String]], যা মিলবে গ্রুপগুলি প্রদান করে।
রাকেন্সী

2
এটা একটি পদ্ধতি StringLike যা ফেরৎ Regex
asm

11
@rakensi নং val r = "[A-Ca-c]".r ; 'a' match { case r() => } scala-lang.org/api/current/#scala.util.matching.Regex
som-snytt

3
@JeremyLeipzig উপেক্ষা Groups: val r = "([A-Ca-c])".r ; "C" match { case r(_*) => }
সোম-স্নিট

120

সংস্করণ ২.১০ থেকে, কেউ স্কালার স্ট্রিং ইন্টারপোলেশন বৈশিষ্ট্যটি ব্যবহার করতে পারে:

implicit class RegexOps(sc: StringContext) {
  def r = new util.matching.Regex(sc.parts.mkString, sc.parts.tail.map(_ => "x"): _*)
}

scala> "123" match { case r"\d+" => true case _ => false }
res34: Boolean = true

আরও ভাল কেউ নিয়মিত প্রকাশের গ্রুপগুলিকে বাঁধতে পারে:

scala> "123" match { case r"(\d+)$d" => d.toInt case _ => 0 }
res36: Int = 123

scala> "10+15" match { case r"(\d\d)${first}\+(\d\d)${second}" => first.toInt+second.toInt case _ => 0 }
res38: Int = 25

আরও বিস্তারিত বাইন্ডিং প্রক্রিয়া সেট করাও সম্ভব:

scala> object Doubler { def unapply(s: String) = Some(s.toInt*2) }
defined module Doubler

scala> "10" match { case r"(\d\d)${Doubler(d)}" => d case _ => 0 }
res40: Int = 20

scala> object isPositive { def unapply(s: String) = s.toInt >= 0 }
defined module isPositive

scala> "10" match { case r"(\d\d)${d @ isPositive()}" => d.toInt case _ => 0 }
res56: Int = 10

যা সম্ভব তা নিয়ে একটি চিত্তাকর্ষক উদাহরণ Dynamicব্লগ পোস্টে ডায়ামিক টাইপের পরিচিতির সাথে দেখানো হয়েছে :

object T {

  class RegexpExtractor(params: List[String]) {
    def unapplySeq(str: String) =
      params.headOption flatMap (_.r unapplySeq str)
  }

  class StartsWithExtractor(params: List[String]) {
    def unapply(str: String) =
      params.headOption filter (str startsWith _) map (_ => str)
  }

  class MapExtractor(keys: List[String]) {
    def unapplySeq[T](map: Map[String, T]) =
      Some(keys.map(map get _))
  }

  import scala.language.dynamics

  class ExtractorParams(params: List[String]) extends Dynamic {
    val Map = new MapExtractor(params)
    val StartsWith = new StartsWithExtractor(params)
    val Regexp = new RegexpExtractor(params)

    def selectDynamic(name: String) =
      new ExtractorParams(params :+ name)
  }

  object p extends ExtractorParams(Nil)

  Map("firstName" -> "John", "lastName" -> "Doe") match {
    case p.firstName.lastName.Map(
          Some(p.Jo.StartsWith(fn)),
          Some(p.`.*(\\w)$`.Regexp(lastChar))) =>
      println(s"Match! $fn ...$lastChar")
    case _ => println("nope")
  }
}

উত্তরটি খুব পছন্দ করেছে, কিন্তু এটি যখন আরইপিএল এর বাইরে ব্যবহার করার চেষ্টা করা হয়েছিল তখন এটি লক হয়ে গেছে (যেমন ঠিক একই কোড যা আরপিএল এ কাজ করেছিল তা চলমান অ্যাপ্লিকেশনটিতে কাজ করে না)। এছাড়াও $সাইনটি লাইন এন্ড প্যাটার্ন হিসাবে ব্যবহার করতে সমস্যা রয়েছে : সংকলক স্ট্রিং সমাপ্তির অভাব সম্পর্কে অভিযোগ করে।
রাজিশ

@ রাজিশ: সমস্যা কী হতে পারে তা জানেন না। আমার উত্তরের সমস্ত কিছুই ২.১০ সাল থেকে কার্যকর।
কিরিতসুকু

@ এসসিএফ: সেই case p.firstName.lastName.Map(...প্যাটার্ন - পৃথিবীতে আমি কীভাবে এটি পড়ি?
এরিক কাপলুন

1
@ এরিক অলিক এটিকে "যখন 'ফার্স্টনেম' 'জো' দিয়ে শুরু হয় এবং ম্যাচটি সফল হয় তার চেয়ে 'সেকেন্ডনাম' প্রদত্ত রেজেক্সের সাথে মিলে যায় এমন কিছু হিসাবে এটি পড়েন"। এটি স্কালাস পাওয়ারের আরও উদাহরণ, আমি উত্পাদন কোডে এই ব্যবহারের ক্ষেত্রে উদাহরণটি লিখব না। বিটিডব্লু, মানচিত্রের ব্যবহারটি একটি তালিকা দ্বারা প্রতিস্থাপন করা উচিত, কারণ মানচিত্রটি সীমানাবিহীন এবং আরও মানগুলির জন্য এটির আর নিশ্চয়তা দেওয়া হয় না যে সঠিক পরিবর্তনশীল ডান ম্যাচারের সাথে মেলে।
কিরিতসুকু

1
এটি দ্রুত প্রোটোটাইপিংয়ের জন্য খুব সুবিধাজনক, তবে নোট করুন যে এটি Regexপ্রতিবার ম্যাচটি পরীক্ষা করার একটি নতুন উদাহরণ তৈরি করে । এবং এটি বেশ ব্যয়বহুল অপারেশন যা রিজেক্স প্যাটার্ন সংকলন জড়িত।
এইচআরজে

51

ডেলানান উল্লেখ করেছেন যে, matchস্কালায় মূলশব্দটির রেজিক্সগুলির সাথে কোনও সম্পর্ক নেই। কোনও স্ট্রিং একটি রেজেক্সের সাথে মেলে কিনা তা জানতে আপনি এই String.matchesপদ্ধতিটি ব্যবহার করতে পারেন । লোয়ার বা উপরের ক্ষেত্রে a, b বা c দিয়ে একটি স্ট্রিং শুরু হয় কিনা তা জানতে, রেজেক্সটি দেখতে এইরকম হবে:

word.matches("[a-cA-C].*")

আপনি এই রেজেক্সটিকে "a, b, c, A, B বা C এর পরে যে কোনও একটি অক্ষর" বলে পড়তে পারেন ( .যার অর্থ "যে কোনও অক্ষর" এবং *যার অর্থ "শূন্য বা আরও বেশি বার", সুতরাং "। *" কোনও স্ট্রিং) ।


25

অ্যান্ড্রুয়ের উত্তরের বিষয়ে কিছুটা প্রসারিত করার জন্য : নিয়মিত এক্সপ্রেশনগুলি এক্সট্র্যাক্টর সংজ্ঞায়িত করে এমন সত্য যে স্কেলার প্যাটার্নের মিলটি ব্যবহার করে খুব সুন্দরভাবে রেজেক্সের সাথে মিলে যাওয়া সাবস্ট্রিংগুলি পচন করতে ব্যবহার করা যেতে পারে:

val Process = """([a-cA-C])([^\s]+)""".r // define first, rest is non-space
for (p <- Process findAllIn "aha bah Cah dah") p match {
  case Process("b", _) => println("first: 'a', some rest")
  case Process(_, rest) => println("some first, rest: " + rest)
  // etc.
}

আমি উচ্চ টুপি দ্বারা সত্যিই বিভ্রান্ত ^ যদিও আমি "^" এর অর্থ "লাইনের শুরুর সাথে মিল"। এটি লাইনের শুরুর সাথে মেলে না।
মাইকেল লাফায়েট

@ মিশেলল্যাফয়েট: একটি অক্ষর শ্রেণীর অভ্যন্তরে ( []) ক্যারেট প্রত্যাখ্যানের ইঙ্গিত দেয়, সুতরাং এর [^\s]অর্থ 'অ-হোয়াইটস্পেস'।
ফ্যাবিয়ান স্টেগ

9

স্ট্রিং.ম্যাচগুলি হ'ল রেজেক্স অর্থে প্যাটার্ন মেলানোর উপায়।

তবে খুব সহজেই সরু হিসাবে, আসল স্কালা কোডে word.firstLetter এর মত দেখাচ্ছে:

word(0)

স্কালা স্ট্রিংসকে চরের সিকোয়েন্স হিসাবে বিবেচনা করে, তাই যদি কোনও কারণে আপনি স্পষ্টভাবে স্ট্রিংয়ের প্রথম চরিত্রটি পেতে চান এবং এটির সাথে মেলে, আপনি এই জাতীয় কিছু ব্যবহার করতে পারেন:

"Cat"(0).toString.matches("[a-cA-C]")
res10: Boolean = true

আমি এটিকে রেজেক্স প্যাটার্ন মেলানোর সাধারণ উপায় হিসাবে প্রস্তাব দিচ্ছি না, তবে এটি প্রথমে কোনও স্ট্রিংয়ের প্রথম চরিত্রটি সন্ধান করতে এবং তারপরে একটি রেজেক্সের সাথে ম্যাচ করার জন্য আপনার প্রস্তাবিত পদ্ধতির সাথে সঙ্গতিপূর্ণ।

সম্পাদনা: স্পষ্ট করে বলতে গেলে, আমি যেভাবে এটি করব তা অন্যরা যেমন বলেছেন:

"Cat".matches("^[a-cA-C].*")
res14: Boolean = true

আপনার প্রাথমিক সিউডোকোডের কাছে যতটা সম্ভব কাছাকাছি একটি উদাহরণ দেখাতে চেয়েছিলেন। চিয়ার্স!


3
"Cat"(0).toStringআরও স্পষ্টভাবে লিখিত হতে পারে "Cat" take 1, imho।
ডেভিড উইনস্লো

এছাড়াও (যদিও এটি একটি পুরানো আলোচনা - আমি সম্ভবত কবর খনন করছি): আপনি '। *' কে শেষ থেকে সরিয়ে ফেলতে পারেন কারণ এটি রেগেক্সে কোনও মান যুক্ত করে না। সবে "বিড়াল"। ম্যাচগুলি ("^ [a-cA-C]")
আকাউপ্পি

আজ 2.11 val r = "[A-Ca-c]".r ; "cat"(0) match { case r() => },।
som-snytt

হাই টুপি (^) এর অর্থ কী?
মাইকেল লাফায়েট

এটি অ্যাঙ্কর যার অর্থ 'লাইনের শুরু' ( cs.duke.edu/csl/docs/unix_course/intro-73.html )। তাই হাই টুপি অনুসরণ করে এমন সমস্ত কিছুই প্যাটার্নের সাথে মিলবে যদি এটি লাইনের প্রথম জিনিস হয়।
জানস

9

নোট করুন যে @ অ্যান্ড্রুমার্সের উত্তর থেকে প্রাপ্ত পদ্ধতির সাথে পুরো স্ট্রিংটি নিয়মিত এক্সপ্রেশনের সাথে মেলে, স্ট্রিংয়ের উভয় প্রান্তে ^এবং ব্যবহার করে স্ট্রিংয়ের উভয় প্রান্তে নিয়মিত অভিব্যক্তি অ্যাঙ্করিংয়ের প্রভাব সহ $। উদাহরণ:

scala> val MY_RE = "(foo|bar).*".r
MY_RE: scala.util.matching.Regex = (foo|bar).*

scala> val result = "foo123" match { case MY_RE(m) => m; case _ => "No match" }
result: String = foo

scala> val result = "baz123" match { case MY_RE(m) => m; case _ => "No match" }
result: String = No match

scala> val result = "abcfoo123" match { case MY_RE(m) => m; case _ => "No match" }
result: String = No match

এবং .*শেষে নেই:

scala> val MY_RE2 = "(foo|bar)".r
MY_RE2: scala.util.matching.Regex = (foo|bar)

scala> val result = "foo123" match { case MY_RE2(m) => m; case _ => "No match" }
result: String = No match

1
আইডোম্যাটিকভাবে val MY_RE2 = "(foo|bar)".r.unanchored ; "foo123" match { case MY_RE2(_*) => },। আরও কৃপণভাবে, val reসমস্ত ক্যাপ ছাড়া।
som-snytt

9

প্রথমে আমাদের জানা উচিত যে নিয়মিত প্রকাশটি আলাদাভাবে ব্যবহার করা যেতে পারে। এখানে একটি উদাহরণ:

import scala.util.matching.Regex
val pattern = "Scala".r // <=> val pattern = new Regex("Scala")
val str = "Scala is very cool"
val result = pattern findFirstIn str
result match {
  case Some(v) => println(v)
  case _ =>
} // output: Scala

দ্বিতীয়টি আমাদের লক্ষ্য করা উচিত যে প্যাটার্ন মিলের সাথে নিয়মিত প্রকাশের সংমিশ্রণ করা খুব শক্তিশালী হবে। এখানে একটি সহজ উদাহরণ।

val date = """(\d\d\d\d)-(\d\d)-(\d\d)""".r
"2014-11-20" match {
  case date(year, month, day) => "hello"
} // output: hello

আসলে, নিয়মিত প্রকাশটি ইতিমধ্যে খুব শক্তিশালী; আমাদের কেবলমাত্র এটি করা দরকার এটি স্কালাকে আরও শক্তিশালী করে তোলা। এখানে Scala ডকুমেন্ট আরও উদাহরণ দেওয়া হল: http://www.scala-lang.org/files/archive/api/current/index.html#scala.util.matching.Regex

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.