সুইফট এক্সট্র্যাক্ট রেগেক্স ম্যাচ


175

আমি একটি স্ট্রিং থেকে সাবস্ট্রিংগুলি বের করতে চাই যা একটি রেজেক্স প্যাটার্নের সাথে মেলে।

সুতরাং আমি এই জাতীয় কিছু খুঁজছি:

func matchesForRegexInText(regex: String!, text: String!) -> [String] {
   ???
}

সুতরাং এই আমার আছে:

func matchesForRegexInText(regex: String!, text: String!) -> [String] {

    var regex = NSRegularExpression(pattern: regex, 
        options: nil, error: nil)

    var results = regex.matchesInString(text, 
        options: nil, range: NSMakeRange(0, countElements(text))) 
            as Array<NSTextCheckingResult>

    /// ???

    return ...
}

সমস্যা যে, matchesInStringআমার একটি অ্যারের বিতরণ NSTextCheckingResult, যেখানে NSTextCheckingResult.rangeধরনের হয় NSRange

NSRangeএর সাথে বেমানান Range<String.Index>, তাই এটি আমাকে ব্যবহার করতে বাধা দেয়text.substringWithRange(...)

কোডের খুব বেশি লাইন ছাড়াই কীভাবে এই সাধারণ জিনিসটি দ্রুতগতিতে অর্জন করা যায়?

উত্তর:


313

এমনকি যদি matchesInString()পদ্ধতিটি Stringপ্রথম আর্গুমেন্ট হিসাবে গ্রহণ করে তবে তা অভ্যন্তরীণভাবে এটির সাথে কাজ করে NSStringএবং সীমা প্যারামিটারটি NSStringদৈর্ঘ্যটি ব্যবহার করে সুইফট স্ট্রিংয়ের দৈর্ঘ্যের হিসাবে নয় অবশ্যই দেওয়া উচিত । অন্যথায় এটি "ফ্ল্যাগস" এর মতো "বর্ধিত গ্রাফি ক্লাস্টার" এর জন্য ব্যর্থ হবে।

এর মতো সুইফট 4 (Xcode 9), সুইফট মান গ্রন্থাগার ফাংশন মধ্যে রূপান্তর করতে উপলব্ধ Range<String.Index> এবং NSRange

func matches(for regex: String, in text: String) -> [String] {

    do {
        let regex = try NSRegularExpression(pattern: regex)
        let results = regex.matches(in: text,
                                    range: NSRange(text.startIndex..., in: text))
        return results.map {
            String(text[Range($0.range, in: text)!])
        }
    } catch let error {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}

উদাহরণ:

let string = "🇩🇪€4€9"
let matched = matches(for: "[0-9]", in: string)
print(matched)
// ["4", "9"]

দ্রষ্টব্য: বাধ্য আনআরপগুলি Range($0.range, in: text)!নিরাপদ কারণ NSRangeপ্রদত্ত স্ট্রিংয়ের একটি স্ট্রিংকে বোঝায় text। তবে আপনি যদি এড়াতে চান তবে ব্যবহার করুন

        return results.flatMap {
            Range($0.range, in: text).map { String(text[$0]) }
        }

পরিবর্তে.


(সুইফট 3 এবং এর আগেরটির জন্য পুরানো উত্তর :)

সুতরাং আপনার প্রদত্ত সুইফট স্ট্রিংটিকে একটিতে রূপান্তর করা উচিত NSStringএবং তারপরে ব্যাপ্তিগুলি বের করতে হবে। ফলাফলটি স্বয়ংক্রিয়ভাবে একটি সুইফ্ট স্ট্রিং অ্যারে রূপান্তরিত হবে।

(স্যুইফট ১.২ এর কোড সম্পাদনা ইতিহাসে পাওয়া যাবে))

সুইফট 2 (এক্সকোড 7.3.1):

func matchesForRegexInText(regex: String, text: String) -> [String] {

    do {
        let regex = try NSRegularExpression(pattern: regex, options: [])
        let nsString = text as NSString
        let results = regex.matchesInString(text,
                                            options: [], range: NSMakeRange(0, nsString.length))
        return results.map { nsString.substringWithRange($0.range)}
    } catch let error as NSError {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}

উদাহরণ:

let string = "🇩🇪€4€9"
let matches = matchesForRegexInText("[0-9]", text: string)
print(matches)
// ["4", "9"]

সুইফট 3 (এক্সকোড 8)

func matches(for regex: String, in text: String) -> [String] {

    do {
        let regex = try NSRegularExpression(pattern: regex)
        let nsString = text as NSString
        let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length))
        return results.map { nsString.substring(with: $0.range)}
    } catch let error {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}

উদাহরণ:

let string = "🇩🇪€4€9"
let matched = matches(for: "[0-9]", in: string)
print(matched)
// ["4", "9"]

9
তুমি আমাকে পাগল হওয়ার হাত থেকে বাঁচিয়েছ। মজা করছি না. তোমাকে অনেক ধন্যবাদ!
মিচকম্যান

1
@ ম্যাথিজসিজারস: আমি সুইফট ১.২ / এক্সকোড .3.৩ এর জন্য কোডটি আপডেট করেছি। আমাকে জানতে দেওয়ার জন্য ধন্যবাদ!
মার্টিন আর 13

1
তবে যদি আমি কোনও ট্যাগের মধ্যে স্ট্রিংগুলি অনুসন্ধান করতে চাই? আমার একই ফলাফল (ম্যাচের তথ্য) যেমন: regex101.com/r/cU6jX8/2 প্রয়োজন । আপনি কোন রেজেক্স প্যাটার্নের পরামর্শ দিবেন?
পিটার ক্রেইঞ্জ 21

আপডেটটি সুইফট
২.২ এর

1
ধন্যবাদ! আপনি যদি কেবলমাত্র রেগেক্সের মধ্যে () এর মধ্যে যা খুঁজে পেতে চান? উদাহরণস্বরূপ, "[0-9] {3} ([0-9] {6})" এ আমি কেবল সর্বশেষ 6 নম্বর পেতে চাই।
p4bloch

64

আমার উত্তর প্রদত্ত উত্তরের উপরে তৈরি করে তবে অতিরিক্ত সমর্থন যুক্ত করে রেগেক্সকে আরও শক্তিশালী করে তোলে:

  • কেবল ম্যাচই দেয় না তবে প্রতিটি ম্যাচের জন্য সমস্ত ক্যাপচারিং গ্রুপও প্রদান করে (নীচের উদাহরণগুলি দেখুন)
  • একটি খালি অ্যারে ফিরিয়ে দেওয়ার পরিবর্তে, এই সমাধানটি alচ্ছিক মিলগুলি সমর্থন করে
  • do/catchকনসোলে মুদ্রণ না করে এড়ানো এবং কনস্ট্রাক্টটি ব্যবহার করেguard
  • matchingStringsএটিকে এক্সটেনশন হিসাবে যুক্ত করেString

সুইফট 4.2

//: Playground - noun: a place where people can play

import Foundation

extension String {
    func matchingStrings(regex: String) -> [[String]] {
        guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] }
        let nsString = self as NSString
        let results  = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length))
        return results.map { result in
            (0..<result.numberOfRanges).map {
                result.range(at: $0).location != NSNotFound
                    ? nsString.substring(with: result.range(at: $0))
                    : ""
            }
        }
    }
}

"prefix12 aaa3 prefix45".matchingStrings(regex: "fix([0-9])([0-9])")
// Prints: [["fix12", "1", "2"], ["fix45", "4", "5"]]

"prefix12".matchingStrings(regex: "(?:prefix)?([0-9]+)")
// Prints: [["prefix12", "12"]]

"12".matchingStrings(regex: "(?:prefix)?([0-9]+)")
// Prints: [["12", "12"]], other answers return an empty array here

// Safely accessing the capture of the first match (if any):
let number = "prefix12suffix".matchingStrings(regex: "fix([0-9]+)su").first?[1]
// Prints: Optional("12")

সুইফট 3

//: Playground - noun: a place where people can play

import Foundation

extension String {
    func matchingStrings(regex: String) -> [[String]] {
        guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] }
        let nsString = self as NSString
        let results  = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length))
        return results.map { result in
            (0..<result.numberOfRanges).map {
                result.rangeAt($0).location != NSNotFound
                    ? nsString.substring(with: result.rangeAt($0))
                    : ""
            }
        }
    }
}

"prefix12 aaa3 prefix45".matchingStrings(regex: "fix([0-9])([0-9])")
// Prints: [["fix12", "1", "2"], ["fix45", "4", "5"]]

"prefix12".matchingStrings(regex: "(?:prefix)?([0-9]+)")
// Prints: [["prefix12", "12"]]

"12".matchingStrings(regex: "(?:prefix)?([0-9]+)")
// Prints: [["12", "12"]], other answers return an empty array here

// Safely accessing the capture of the first match (if any):
let number = "prefix12suffix".matchingStrings(regex: "fix([0-9]+)su").first?[1]
// Prints: Optional("12")

সুইফট 2

extension String {
    func matchingStrings(regex: String) -> [[String]] {
        guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] }
        let nsString = self as NSString
        let results  = regex.matchesInString(self, options: [], range: NSMakeRange(0, nsString.length))
        return results.map { result in
            (0..<result.numberOfRanges).map {
                result.rangeAtIndex($0).location != NSNotFound
                    ? nsString.substringWithRange(result.rangeAtIndex($0))
                    : ""
            }
        }
    }
}

1
ক্যাপচার গ্রুপগুলি সম্পর্কে ভাল ধারণা। তবে "গার্ড" সুইফটিয়ার "ডু / ক্যাচ" এর চেয়ে কেন ??
মার্টিন আর

আমি nshipster.com/guard- এবং-defer এর মতো লোকদের সাথে একমত যারা যারা বলে যে সুইফট ২.০ অবশ্যই বয়সের বিবরণে বাসা বাঁধার পরিবর্তে প্রাথমিকভাবে ফিরে যাওয়ার একটি স্টাইলকে [...] উত্সাহিত করছে বলে মনে হচ্ছে । একইভাবে নেস্টেড ডু / ক্যাচ স্টেটমেন্ট আইএমএইচও-র ক্ষেত্রে সত্য।
লার্স ব্লামবার্গ

ট্রাই / ক্যাচ হ'ল সুইফটে দেশীয় ত্রুটি পরিচালনা করা। try?যদি আপনি কেবল কলটির ফলাফলের প্রতি আগ্রহী হন তবে কোনও সম্ভাব্য ত্রুটি বার্তায় নয় তবে ব্যবহার করা যেতে পারে। হ্যাঁ, guard try? ..ঠিক আছে, তবে আপনি যদি ত্রুটিটি মুদ্রণ করতে চান তবে আপনার একটি ডো-ব্লক দরকার। উভয় উপায় সুইফটি।
মার্টিন আর

3
আমি আপনার সুন্দর স্নিপেটে ইউনিটসেট যুক্ত করেছি, gist.github.com/neoneye/03cbb26778539ba5eb609d16200e4522
নিউনি

1
আমি এটি না হওয়া পর্যন্ত @ মার্টিনআর উত্তরের উপর ভিত্তি করে আমার নিজের লিখতে চলেছি। ধন্যবাদ!
অর্টিম

13

আপনি যদি কোনও স্ট্রিং থেকে সাবস্ট্রিংগুলি বের করতে চান, কেবল অবস্থান নয়, (তবে ইমোজিস সহ প্রকৃত স্ট্রিং) তারপরে, নিম্নলিখিতগুলি সম্ভবত একটি সহজ সমাধান।

extension String {
  func regex (pattern: String) -> [String] {
    do {
      let regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions(rawValue: 0))
      let nsstr = self as NSString
      let all = NSRange(location: 0, length: nsstr.length)
      var matches : [String] = [String]()
      regex.enumerateMatchesInString(self, options: NSMatchingOptions(rawValue: 0), range: all) {
        (result : NSTextCheckingResult?, _, _) in
        if let r = result {
          let result = nsstr.substringWithRange(r.range) as String
          matches.append(result)
        }
      }
      return matches
    } catch {
      return [String]()
    }
  }
} 

ব্যবহারের উদাহরণ:

"someText 👿🏅👿⚽️ pig".regex("👿⚽️")

নিম্নলিখিতগুলি ফেরত দেবেন:

["👿⚽️"]

"\ W +" ব্যবহার করে একটি অপ্রত্যাশিত উত্পাদন "" নোট করুন

"someText 👿🏅👿⚽️ pig".regex("\\w+")

এই স্ট্রিং অ্যারে ফিরিয়ে দেবে

["someText", "️", "pig"]

1
এটি আমি চেয়েছিলাম
কাইল কিম

1
নিস! এটি সুইফট 3 এর জন্য সামান্য সমন্বয় প্রয়োজন, তবে এটি দুর্দান্ত।
জেলি

@ জেল এটির সামঞ্জস্য প্রয়োজন কী? আমি দ্রুত 5.1.3 ব্যবহার করছি
পিটার শোর্ন

9

আমি দেখেছি যে গৃহীত উত্তরের সমাধান দুর্ভাগ্যক্রমে লিনাক্সের জন্য সুইফট 3-এ সংকলন করে না। এখানে একটি পরিবর্তিত সংস্করণ রয়েছে, তবে এটি করে:

import Foundation

func matches(for regex: String, in text: String) -> [String] {
    do {
        let regex = try RegularExpression(pattern: regex, options: [])
        let nsString = NSString(string: text)
        let results = regex.matches(in: text, options: [], range: NSRange(location: 0, length: nsString.length))
        return results.map { nsString.substring(with: $0.range) }
    } catch let error {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}

প্রধান পার্থক্যগুলি হ'ল:

  1. লিনাক্সের উপর সুইফ্টের NSজন্য ফাউন্ডেশন অবজেক্টগুলিতে উপসর্গটি ফেলে দেওয়া প্রয়োজন মনে হয় যার জন্য কোনও সুইফট-নেটিভ সমতুল্য নেই। ( সুইফট বিবর্তনের প্রস্তাব # 86 দেখুন ))

  2. লিনাক্স অন সুইফট এছাড়াও আরম্ভ এবং পদ্ধতি optionsউভয় জন্য আর্গুমেন্ট নির্দিষ্ট করা প্রয়োজন ।RegularExpressionmatches

  3. কিছু কারণে, উপর চাপ একটি Stringএকটি মধ্যে NSStringলিনাক্স সুইফট কাজ করে না কিন্তু একটি নতুন আরম্ভের NSStringএকটি সঙ্গে Stringউৎস হিসেবে কাজ করে।

আপনার NSRegularExpressionপরিবর্তে নামটি ব্যবহার করা আবশ্যক একমাত্র ব্যতিক্রম সহ এই সংস্করণটি ম্যাকোস / এক্সকোডে সুইফট 3 এর সাথেও কাজ করে RegularExpression


5

@ p4bloch আপনি যদি ক্যাপচার করা প্রথম বন্ধনী থেকে ফলাফলগুলি ক্যাপচার করতে চান তবে তার পরিবর্তে আপনাকে এর rangeAtIndex(index)পদ্ধতিটি ব্যবহার করতে NSTextCheckingResultহবে range। উপরে থেকে সুইফট 2 এর জন্য @ মার্টিনআর'র পদ্ধতিটি এখানে ক্যাপচার করা প্রথম বন্ধনী হিসাবে অভিযোজিত। ফিরে আসা অ্যারেতে, প্রথম ফলাফলটি [0]সম্পূর্ণ ক্যাপচার এবং তারপরে স্বতন্ত্র ক্যাপচার গ্রুপগুলি শুরু হয় [1]। আমি mapঅপারেশনটি মন্তব্য করেছি (যাতে আমি কী বদলেছি তা দেখতে আরও সহজ) এবং এটিকে নেস্টেড লুপগুলি দিয়ে প্রতিস্থাপন করেছি।

func matches(for regex: String!, in text: String!) -> [String] {

    do {
        let regex = try NSRegularExpression(pattern: regex, options: [])
        let nsString = text as NSString
        let results = regex.matchesInString(text, options: [], range: NSMakeRange(0, nsString.length))
        var match = [String]()
        for result in results {
            for i in 0..<result.numberOfRanges {
                match.append(nsString.substringWithRange( result.rangeAtIndex(i) ))
            }
        }
        return match
        //return results.map { nsString.substringWithRange( $0.range )} //rangeAtIndex(0)
    } catch let error as NSError {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}

উদাহরণ ব্যবহারের ক্ষেত্রে হতে পারে, বলুন যে আপনি উদাহরণটির একটি স্ট্রিংকে বিভক্ত করতে চান title yearউদাহরণস্বরূপ "ফাইন্ডিং ডরি 2016" আপনি এটি করতে পারেন:

print ( matches(for: "^(.+)\\s(\\d{4})" , in: "Finding Dory 2016"))
// ["Finding Dory 2016", "Finding Dory", "2016"]

এই উত্তর আমার দিন তৈরি। আমি এমন একটি সমাধান অনুসন্ধান করতে 2 ঘন্টা ব্যয় করেছি যা গ্রুপগুলির অতিরিক্ত ক্যাপচারের মাধ্যমে নিয়মিত অভিব্যক্তিটি সন্তুষ্ট করতে পারে।
আহমাদ

এটি কাজ করে তবে কোনও ব্যাপ্তি না পাওয়া গেলে এটি ক্রাশ হবে। আমি এই কোডটি সংশোধন করেছি যাতে ফাংশনটি ফিরে আসে [String?]এবং for i in 0..<result.numberOfRangesব্লকটিতে আপনাকে একটি পরীক্ষা যোগ করতে হবে যা কেবলমাত্র পরিসীমা মিলিয়ে ম্যাচটি NSNotFoundসংযোজন করে ! = অন্যথায় এটি শূন্য করা উচিত। দেখুন: stackoverflow.com/a/31892241/2805570
stef

4

এনএসএসস্ট্রিং ছাড়াই সুইফট 4।

extension String {
    func matches(regex: String) -> [String] {
        guard let regex = try? NSRegularExpression(pattern: regex, options: [.caseInsensitive]) else { return [] }
        let matches  = regex.matches(in: self, options: [], range: NSMakeRange(0, self.count))
        return matches.map { match in
            return String(self[Range(match.range, in: self)!])
        }
    }
}

উপরের সমাধানটি সম্পর্কে সতর্কতা অবলম্বন করুন: NSMakeRange(0, self.count)সঠিক নয়, কারণ selfএটি একটি String(= ইউটিএফ 8) এবং একটি NSString(= ইউটিএফ 16) নয়। সুতরাং self.countঅগত্যা এটির মতো নয় nsString.length(অন্যান্য সমাধান হিসাবে ব্যবহৃত হয়)। আপনি রেঞ্জের গণনা প্রতিস্থাপন করতে পারেনNSRange(self.startIndex..., in: self)
pd95

3

উপরের বেশিরভাগ সমাধান কেবল ক্যাপচার গ্রুপগুলিকে উপেক্ষা করে পুরো ম্যাচটি দেয় যেমন: ^ \ d + \ s + (\ d +)

ক্যাপচার গ্রুপটি প্রত্যাশার মতো মিলগুলি পেতে আপনার (সুইফট 4) এর মতো কিছু দরকার:

public extension String {
    public func capturedGroups(withRegex pattern: String) -> [String] {
        var results = [String]()

        var regex: NSRegularExpression
        do {
            regex = try NSRegularExpression(pattern: pattern, options: [])
        } catch {
            return results
        }
        let matches = regex.matches(in: self, options: [], range: NSRange(location:0, length: self.count))

        guard let match = matches.first else { return results }

        let lastRangeIndex = match.numberOfRanges - 1
        guard lastRangeIndex >= 1 else { return results }

        for i in 1...lastRangeIndex {
            let capturedGroupIndex = match.range(at: i)
            let matchedString = (self as NSString).substring(with: capturedGroupIndex)
            results.append(matchedString)
        }

        return results
    }
}

এটি দুর্দান্ত যদি আপনি কেবল প্রথম ফলাফল চান, প্রতিটি ফলাফলের for index in 0..<matches.count {চারপাশে প্রয়োজনীয় ফলাফল পেতেlet lastRange... results.append(matchedString)}
জিওফ

দফার জন্য for i in 1...lastRangeIndex { let capturedGroupIndex = match.range(at: i) if capturedGroupIndex.location != NSNotFound { let matchedString = (self as NSString).substring(with: capturedGroupIndex) results.append(matchedString.trimmingCharacters(in: .whitespaces)) } }
দৃষ্টিকোণটি দেখতে হবে

2

আমি এটি কীভাবে করেছি, আমি আশা করি এটি কীভাবে সুইফটে কাজ করে এটি একটি নতুন দৃষ্টিকোণ নিয়ে আসে।

নীচের এই উদাহরণে আমি এর মধ্যে যে কোনও স্ট্রিং পাব []

var sample = "this is an [hello] amazing [world]"

var regex = NSRegularExpression(pattern: "\\[.+?\\]"
, options: NSRegularExpressionOptions.CaseInsensitive 
, error: nil)

var matches = regex?.matchesInString(sample, options: nil
, range: NSMakeRange(0, countElements(sample))) as Array<NSTextCheckingResult>

for match in matches {
   let r = (sample as NSString).substringWithRange(match.range)//cast to NSString is required to match range format.
    println("found= \(r)")
}

2

এটি একটি খুব সহজ সমাধান যা ম্যাচগুলির সাথে স্ট্রিংয়ের একটি অ্যারে প্রদান করে

সুইফট 3।

internal func stringsMatching(regularExpressionPattern: String, options: NSRegularExpression.Options = []) -> [String] {
        guard let regex = try? NSRegularExpression(pattern: regularExpressionPattern, options: options) else {
            return []
        }

        let nsString = self as NSString
        let results = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length))

        return results.map {
            nsString.substring(with: $0.range)
        }
    }

2

সমস্ত ম্যাচ ফেরত দেওয়ার দ্রুততম উপায় এবং সুইফট 5-তে গ্রুপগুলি ক্যাপচার করুন

extension String {
    func match(_ regex: String) -> [[String]] {
        let nsString = self as NSString
        return (try? NSRegularExpression(pattern: regex, options: []))?.matches(in: self, options: [], range: NSMakeRange(0, count)).map { match in
            (0..<match.numberOfRanges).map { match.range(at: $0).location == NSNotFound ? "" : nsString.substring(with: match.range(at: $0)) }
        } ?? []
    }
}

স্ট্রিংগুলির একটি 2-মাত্রিক অ্যারে প্রদান করে:

"prefix12suffix fix1su".match("fix([0-9]+)su")

আয় ...

[["fix12su", "12"], ["fix1su", "1"]]

// First element of sub-array is the match
// All subsequent elements are the capture groups

0

সুইফট 4 এর সাথে গ্রুপ এবং পুরো ম্যাচগুলি ক্যাপচারের জন্য তার উত্তরটি লার্স ব্লম্বার্গের জন্য ধন্যবাদ , যা আমাকে অনেক সাহায্য করেছিল। আমি সেই লোকেদের জন্য এটির সংযোজনও করেছি, যারা ত্রুটি চায়। লোকালাইজড বিবরণ প্রতিক্রিয়া যখন তাদের রেজেক্স অবৈধ থাকে:

extension String {
    func matchingStrings(regex: String) -> [[String]] {
        do {
            let regex = try NSRegularExpression(pattern: regex)
            let nsString = self as NSString
            let results  = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length))
            return results.map { result in
                (0..<result.numberOfRanges).map {
                    result.range(at: $0).location != NSNotFound
                        ? nsString.substring(with: result.range(at: $0))
                        : ""
                }
            }
        } catch let error {
            print("invalid regex: \(error.localizedDescription)")
            return []
        }
    }
}

আমার স্থানীয়করণের বিবরণী ত্রুটি হিসাবে থাকার ফলে পালানোর ক্ষেত্রে কী ভুল হয়েছে তা বুঝতে সহায়তা করেছে, যেহেতু এটি প্রদর্শিত হয় যে চূড়ান্ত রেজেক্স সুইফট বাস্তবায়নের চেষ্টা করে।

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