আপার বনাম লোয়ার কেস


86

কেস-সংবেদনশীল তুলনা করার সময়, স্ট্রিংটি আপার কেস বা লোয়ার কেসে রূপান্তর করা আরও দক্ষ? এটা কি কোন ব্যাপার?

এই এসও পোস্টে পরামর্শ দেওয়া হয়েছে যে সি # টুপারের সাথে আরও দক্ষ কারণ "মাইক্রোসফ্ট সেভাবে এটি অপ্টিমাইজ করেছে।" তবে আমিও পড়েছি এই যুক্তিটিও যে টোলওয়ার বনাম টুউপার রূপান্তর করা আপনার স্ট্রিংগুলিতে কী বেশি থাকে তার উপর নির্ভর করে এবং সাধারণত স্ট্রিংগুলিতে আরও ছোট হাতের অক্ষর থাকে যা টোলওয়ারকে আরও দক্ষ করে তোলে।

বিশেষত, আমি জানতে চাই:

  • টুঅপার বা টোলওয়ারকে এমনভাবে অপ্টিমাইজ করার কোনও উপায় আছে যেটি অন্যটির চেয়ে দ্রুততর হয়?
  • আপার বা লোয়ার কেস স্ট্রিংয়ের মধ্যে কেস-সংবেদনশীল তুলনা করা কি দ্রুত এবং কেন?
  • এমন কি কোনও প্রোগ্রামিং পরিবেশ রয়েছে (যেমন, সি, সি #, পাইথন, যাই হোক না কেন) যেখানে একটির মামলা অন্যটির চেয়ে পরিষ্কার হয় এবং কেন?

উত্তর:


90

কিছু সংস্কৃতির বিশেষত তুরস্কের "আকর্ষণীয়" বৈশিষ্ট্যগুলির কারণে কেস-সংবেদনশীল তুলনা করতে উচ্চতর ক্ষেত্রে বা নিম্নতর কেস রূপান্তর করা ভুল। পরিবর্তে, একটি স্ট্রিংকম্পার ব্যবহার করুন উপযুক্ত বিকল্পগুলির সাথে করুন।

এমএসডিএন-এর স্ট্রিং হ্যান্ডলিং সম্পর্কিত কয়েকটি দুর্দান্ত নির্দেশিকা রয়েছে। আপনার কোডটি তুরস্কের পরীক্ষায় পাস করেছে তাও আপনি দেখতে চাইতে পারেন ।

সম্পাদনা: নীল এর মন্তব্যটি অর্ডিনাল কেস-সংবেদনশীল তুলনাগুলি সম্পর্কে নোট করুন । এই পুরো রাজ্যটি বেশ সরল :(


15
হ্যাঁ স্ট্রিংকম্পার দুর্দান্ত, তবে প্রশ্নের উত্তর দেওয়া হয়নি ... আপনি স্ট্রিংকম্পারার যেমন স্ট্রিংয়ের বিরুদ্ধে সুইচ স্টেটমেন্ট ব্যবহার করতে পারবেন না এমন পরিস্থিতিতে; আমি কি সুইচ এ টুঅপার বা টোলওয়ার উচিত?
joshperry

7
টুঅপার বা টুএলভার ব্যবহার না করে একটি স্ট্রিংকম্পার এবং "যদি" / "অন্য" ব্যবহার করুন।
জন স্কিটি

4
জন, আমি জানি যে লোয়ার কেসে রূপান্তর করা ভুল, তবে আমি শুনিনি যে বড় হাতের রূপান্তরটি ভুল। আপনি একটি উদাহরণ বা একটি রেফারেন্স দিতে পারেন? আপনি যে এমএসডিএন নিবন্ধটি যুক্ত করেছেন এটি এটিকে বলেছে: "অর্ডিনালআইগনোরকেস ব্যবহার করে করা তুলনাগুলি আচরণগতভাবে দুটি কলের সংমিশ্রণ: উভয় স্ট্রিং আর্গুমেন্টে টুউপারআইভারেন্টকে ডেকে পাঠানো এবং একটি সাধারণ তুলনা করা।" "অর্ডিনাল স্ট্রিং অপারেশনস" শীর্ষক বিভাগে, এটি কোডে এটি পুনরায় সেট করে।
নীল

4
@ নীল: আকর্ষণীয়, আমি কিছুটা দেখিনি। একটি জন্য পূরণবাচক কেস-অবশ তুলনা, আমি যে ন্যায্য যথেষ্ট। এটা কিছু বাছাই করা আছে , সর্বোপরি। সাংস্কৃতিকভাবে সংবেদনশীল কেস-সংবেদনশীল তুলনাগুলির জন্য, আমি মনে করি এখনও কিছু অদ্ভুত আচরণের সুযোগ থাকবে। উত্তরে আপনার মন্তব্য তুলে
ধরবে

4
@ ত্রিনকো: আমি মনে করি যে প্রাথমিকভাবে সঠিকতার দিকে মনোনিবেশ করা জরুরী , কারণ এই ভুল উত্তরটি ধীরে ধীরে পাওয়ার চেয়ে দ্রুত উত্তর পাওয়া সাধারণত ভাল আর (এবং কখনও কখনও খারাপ )ও হয় না।
জন স্কেটি

25

থেকে মাইক্রোসফট দুটিই MSDN করুন:

.NET ফ্রেমওয়ার্কে স্ট্রিংগুলি ব্যবহারের জন্য সেরা অভ্যাস

স্ট্রিং ব্যবহারের জন্য সুপারিশ

কেন? মাইক্রোসফ্ট থেকে :

বড় হাতের স্ট্রিংগুলিকে সাধারণ করুন

অক্ষরের একটি ছোট গ্রুপ রয়েছে যা লোয়ারকেসে রূপান্তরিত হলে কোনও রাউন্ড ট্রিপ করতে পারে না।

এমন চরিত্রের উদাহরণ কী যা একটি বৃত্তাকার ভ্রমণ করতে পারে না?

  • শুরু : গ্রীক রোহ প্রতীক (U + 03f1) ϱ ϱ
  • বড় হাতের অক্ষর : মূলধন গ্রীক রোহ (U + 03a1) Ρ Ρ
  • লোয়ারকেস : ছোট গ্রীক রোহ (U + 03c1) ρ ρ

ϱ, Ρ , ρ

.নাইট ফিডল

Original: ϱ
ToUpper: Ρ
ToLower: ρ

এই কারণেই, যদি আপনি কেস সংবেদনশীল তুলনা করতে চান তবে আপনি স্ট্রিংগুলি বড় হাতের মধ্যে রূপান্তর করেন, এবং ছোট হাতের না।

সুতরাং আপনার যদি একটি চয়ন করতে হয় তবে বড় হাতের বাছাই করুন


4
মূল প্রশ্নের উত্তরে ফিরে যান: একটি বড় হাতের অক্ষরের জন্য একাধিক লোয়ার কেস ভেরিয়েন্ট জানার ভাষা রয়েছে। কোন উপস্থাপনাটি কখন ব্যবহার করবেন সে সম্পর্কে আপনি যদি না জানেন তবে (গ্রীক ভাষায় আরেকটি উদাহরণ: ছোট সিগমা অক্ষর, আপনি word শব্দের শুরুতে বা মাঝখানে, the শব্দের শেষে ( en.wikedia.org/wiki/Sigma দেখুন ), আপনি নিরাপদভাবে ছোট হাতের বৈকল্পিক ফিরে রূপান্তর করতে পারবে না।
আকনকাগুয়া

আসলে জার্মান 'about' সম্পর্কে কী, আপনি যদি ToUpper()এটি কল করেন তবে এটি অনেক সিস্টেমে 'এসএস' তে পরিণত হবে। সুতরাং এটি আসলে রাউন্ড ট্রিপ-সক্ষম হয় না।
সেবাস্তিয়ান

মাইক্রোসফ্ট যদি বড় হাতের তুলনা সম্পাদনের জন্য কোডটি অনুকূলিত করে থাকে তবে এটি হ'ল বড় হাতের অক্ষরের জন্য ASCII কোডটি কেবল দুটি অঙ্ক 65 - 90 অন্যদিকে ASCII কোড ছোট হাতের অক্ষর 97 -122 যেখানে 3 ডিজিট রয়েছে (আরও প্রসেসিং প্রয়োজন)
মেডো মেডো

এটি লক্ষ করা উচিত যে "ϱ" এবং "both" উভয়ই নিজের থেকে ফিরে আসে ToUpperInvariant(), তাই বড় হাতের চেয়ে ছোট হাতের চেয়ে কেন ভাল হয় তার প্রকৃত উদাহরণগুলি দেখতে এখনও ভাল
লাগবে

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

18

এমএসডিএন অনুসারে স্ট্রিংগুলিতে পাস করার ক্ষেত্রে কেস উপেক্ষা করার তুলনাটি বলা আরও দক্ষ:

স্ট্রিং.ক্যাম্পারে (স্ট্র্যাং, আরআরবি, স্ট্রিংকম্পিউশন।অর্ডিনালআইগনোর কেস ) কল করার সমান ( তবে এর চেয়ে দ্রুত )

স্ট্রিং.কম্পের (টুপারআইভারিয়ানেট (স্ট্রিয়া), টুঅপারআইভারিয়ানেট (টিআরবি), স্ট্রিংকোম্পিয়ারি.আরডিনাল)।

এই তুলনাগুলি এখনও খুব দ্রুত।

অবশ্যই, আপনি যদি একটি স্ট্রিংকে বারবার তুলনা করে থাকেন তবে এটি ধরে রাখতে পারে না।


11

আরও ছোট হাতের প্রবেশের জন্য স্ট্রিংয়ের উপর ভিত্তি করে, ToLower তাত্ত্বিকভাবে দ্রুত হওয়া উচিত (প্রচুর তুলনা করা, তবে কয়েকটি অ্যাসাইনমেন্ট)।

সিতে বা প্রতিটি স্ট্রিংয়ের (যেমন সি স্ট্রিং বা এসটিএল এর স্ট্রিং টাইপ সি ++ এর) স্বতন্ত্রভাবে অ্যাক্সেসযোগ্য উপাদান ব্যবহার করার সময় এটি আসলে একটি বাইট তুলনা - সুতরাং তুলনা করা এর UPPERচেয়ে আলাদা নয় lower

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

কোনটি দ্রুত তা আপনার কেন জানতে হবে? আপনি তুলনা একটি মেট্রিক বোতল লোড না করে, একটি কয়েক চক্র দ্রুত চালানো একজন সামগ্রিক প্রয়োগের গতির সাথে অপ্রাসঙ্গিক, এবং অকাল অপ্টিমাইজেশনের মতো শোনাচ্ছে :)


11
কোনটি দ্রুততর তা আমার কেন জানতে হবে এমন প্রশ্নের উত্তর দিতে: আমার জানার দরকার নেই, আমি কেবল জানতে চাই। :) এটি কারও দাবি করা দেখার মতো ঘটনা (যেমন "আপার ক্ষেত্রে স্ট্রিংগুলির তুলনা দ্রুত হয়!") এবং এটি সত্য এবং সত্যই সত্য কিনা এবং / অথবা তারা কেন এই দাবি করেছে তা জানতে চেয়েছিলেন।
পরম্প্পা

4
এই অর্থটি তৈরি করে - আমি এ জাতীয় স্টাফগুলিতে চিরন্তন কৌতূহলীও আছি :)
ওয়ারেন ২

4
সি স্ট্রিং সহ, রূপান্তর করতে sএবং tদীর্ঘস্থায়ী অ্যারেগুলিতে যেমন স্ট্রিং সমান হয় যদি অ্যারে সমান হয় তবে আপনি শেষের '\0'চরিত্র না পাওয়া পর্যন্ত আপনাকে s এবং t দিয়ে যেতে হবে (অন্যথায় আপনি স্ট্রিংয়ের শেষের সাথে আবর্জনার তুলনা করতে পারেন, এটি একটি অবৈধ মেমরি অ্যাক্সেস হতে পারে যা অপরিজ্ঞাত আচরণের জন্য প্রার্থনা করে)। তবে কেন একের পর এক চরিত্রের উপর দিয়ে হাঁটার সময় তুলনা করা হবে না? সি ++ স্ট্রিংগুলির সাহায্যে আপনি সম্ভবত দৈর্ঘ্যটি পেতে পারেন এবং একটিতে .c_str()কাস্ট করতে পারেন এবং দৈর্ঘ্যের long *একটি উপসর্গ তুলনা করতে পারেন .size() - .size()%(sizeof long)। আমাকে কিছুটা ফিশ করে দেখায়, ওহো।
জোনাস কলকার

@ JonasKölker - একটি অ্যারের মধ্যে স্ট্রিং লোড longগুলি শুধু তুলনা দোহাই জন্য নির্বোধ হতে হবে। তবে আপনি যদি এটি "প্রচুর পরিমাণে" করছেন - আমি এটি করার জন্য একটি সম্ভাব্য যুক্তি দেখতে পেতাম ।
ওয়ারেন

5

মাইক্রোসফ্ট অপ্টিমাইজড হয়েছে ToUpperInvariant(), না ToUpper()। পার্থক্যটি হ'ল আক্রমণকারী আরও বেশি সংস্কৃতি বান্ধব। সংস্কৃতিতে ভিন্ন হতে পারে এমন স্ট্রিংগুলির ক্ষেত্রে আপনার যদি কেস-সংবেদনশীল তুলনা করার দরকার হয় তবে ইনভেআরেন্ট ব্যবহার করুন, অন্যথায় অদম্য রূপান্তরটির পারফরম্যান্সটি গুরুত্বপূর্ণ নয়।

টুঅপার () বা টুলওয়ার () যদিও দ্রুত কিনা তা আমি বলতে পারি না। পারফরম্যান্স যে এতটাই গুরুত্বপূর্ণ যে এমন পরিস্থিতি আমার আগে কখনও আসেনি সেহেতু আমি এটি চেষ্টা করিনি


মাইক্রোসফ্ট যদি বড় হাতের তুলনা সম্পাদনের জন্য কোডটি অনুকূলিত করে থাকে তবে এটি কি কারণ বড় হাতের অক্ষরের জন্য ASCII কোডটি মাত্র দুটি অঙ্ক 65 - 90 হয় যখন ASCII কোড ছোট হাতের অক্ষর 97 -122 থাকে যেখানে 3 ডিজিট থাকে (আরও প্রসেসিং প্রয়োজন)?
মেডো মেডো

4
@ মেদো আমি অপ্টিমাইজেশনের সঠিক কারণগুলি মনে করতে পারি না, তবে 2 বনাম 3 সংখ্যা প্রায় কারণই নয় কারণ সমস্ত অক্ষর বাইনারি সংখ্যা হিসাবে সংরক্ষণ করা হয়, তাই দশমিক সংখ্যাগুলি যেভাবে সংরক্ষণ করা হয় তার ভিত্তিতে তার সত্যিকার অর্থে কোনও অর্থ হয় না s
ড্যান হারবার্ট

3

আপনি যদি সি # তে স্ট্রিং তুলনা করছেন তবে এটি উভয় স্ট্রিংকে আপার বা লোয়ার কেসে রূপান্তরিত করার পরিবর্তে ব্যবহারযোগ্যভাবে দ্রুতগতি সম্পন্ন হয় qu .Equals () ব্যবহারের জন্য আরও একটি বড় প্লাস হ'ল 2 টি নতুন নতুন উপরের / লোয়ার কেসগুলির জন্য আরও মেমরি বরাদ্দ করা হয় না।


4
এবং বোনাস হিসাবে, আপনি যদি সঠিক বিকল্পগুলি বেছে নেন তবে এটি আপনাকে সঠিক ফলাফল দেবে :)
জন স্কিটি

0

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


0

এটি সঠিকভাবে করা, আপনি যদি ছোট কেসে রূপান্তর করেন তবে একটি ছোট, তুচ্ছ গতির সুবিধা হওয়া উচিত, তবে এটি হ'ল অনেকেই ইঙ্গিত করেছেন, সংস্কৃতি নির্ভর এবং ফাংশনে উত্তরাধিকারসূত্রে নয় তবে স্ট্রিংগুলিতে আপনি রূপান্তর করেছেন (প্রচুর ছোট অক্ষরের অক্ষর মেমোরিতে কয়েকটি অ্যাসাইনমেন্ট) এর অর্থ - আপনার যদি প্রচুর আপার কেস অক্ষরের স্ট্রিং থাকে তবে আপার কেসে রূপান্তর করা দ্রুত হয়।


0

আমি এটিতে কিছু প্রকৃত ডেটা চেয়েছিলাম, তাই বা দুটি বাইট অক্ষরের পুরো তালিকাটি টানলাম যা ToLowerবা এর সাথে ব্যর্থ হয় ToUpper। আমি তখন নীচে এই পরীক্ষা চালিয়েছি:

using System;

class Program {
   static void Main() {
      char[][] pairs = {
new[]{'\u00E5','\u212B'},new[]{'\u00C5','\u212B'},new[]{'\u0399','\u1FBE'},
new[]{'\u03B9','\u1FBE'},new[]{'\u03B2','\u03D0'},new[]{'\u03B5','\u03F5'},
new[]{'\u03B8','\u03D1'},new[]{'\u03B8','\u03F4'},new[]{'\u03D1','\u03F4'},
new[]{'\u03B9','\u1FBE'},new[]{'\u0345','\u03B9'},new[]{'\u0345','\u1FBE'},
new[]{'\u03BA','\u03F0'},new[]{'\u00B5','\u03BC'},new[]{'\u03C0','\u03D6'},
new[]{'\u03C1','\u03F1'},new[]{'\u03C2','\u03C3'},new[]{'\u03C6','\u03D5'},
new[]{'\u03C9','\u2126'},new[]{'\u0392','\u03D0'},new[]{'\u0395','\u03F5'},
new[]{'\u03D1','\u03F4'},new[]{'\u0398','\u03D1'},new[]{'\u0398','\u03F4'},
new[]{'\u0345','\u1FBE'},new[]{'\u0345','\u0399'},new[]{'\u0399','\u1FBE'},
new[]{'\u039A','\u03F0'},new[]{'\u00B5','\u039C'},new[]{'\u03A0','\u03D6'},
new[]{'\u03A1','\u03F1'},new[]{'\u03A3','\u03C2'},new[]{'\u03A6','\u03D5'},
new[]{'\u03A9','\u2126'},new[]{'\u0398','\u03F4'},new[]{'\u03B8','\u03F4'},
new[]{'\u03B8','\u03D1'},new[]{'\u0398','\u03D1'},new[]{'\u0432','\u1C80'},
new[]{'\u0434','\u1C81'},new[]{'\u043E','\u1C82'},new[]{'\u0441','\u1C83'},
new[]{'\u0442','\u1C84'},new[]{'\u0442','\u1C85'},new[]{'\u1C84','\u1C85'},
new[]{'\u044A','\u1C86'},new[]{'\u0412','\u1C80'},new[]{'\u0414','\u1C81'},
new[]{'\u041E','\u1C82'},new[]{'\u0421','\u1C83'},new[]{'\u1C84','\u1C85'},
new[]{'\u0422','\u1C84'},new[]{'\u0422','\u1C85'},new[]{'\u042A','\u1C86'},
new[]{'\u0463','\u1C87'},new[]{'\u0462','\u1C87'}
      };
      int upper = 0, lower = 0;
      foreach (char[] pair in pairs) {
         Console.Write(
            "U+{0:X4} U+{1:X4} pass: ",
            Convert.ToInt32(pair[0]),
            Convert.ToInt32(pair[1])
         );
         if (Char.ToUpper(pair[0]) == Char.ToUpper(pair[1])) {
            Console.Write("ToUpper ");
            upper++;
         } else {
            Console.Write("        ");
         }
         if (Char.ToLower(pair[0]) == Char.ToLower(pair[1])) {
            Console.Write("ToLower");
            lower++;
         }
         Console.WriteLine();
      }
      Console.WriteLine("upper pass: {0}, lower pass: {1}", upper, lower);
   }
}

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

U+00E5 U+212B pass:         ToLower
U+00C5 U+212B pass:         ToLower
U+0399 U+1FBE pass: ToUpper
U+03B9 U+1FBE pass: ToUpper
U+03B2 U+03D0 pass: ToUpper
U+03B5 U+03F5 pass: ToUpper
U+03B8 U+03D1 pass: ToUpper
U+03B8 U+03F4 pass:         ToLower
U+03D1 U+03F4 pass:
U+03B9 U+1FBE pass: ToUpper
U+0345 U+03B9 pass: ToUpper
U+0345 U+1FBE pass: ToUpper
U+03BA U+03F0 pass: ToUpper
U+00B5 U+03BC pass: ToUpper
U+03C0 U+03D6 pass: ToUpper
U+03C1 U+03F1 pass: ToUpper
U+03C2 U+03C3 pass: ToUpper
U+03C6 U+03D5 pass: ToUpper
U+03C9 U+2126 pass:         ToLower
U+0392 U+03D0 pass: ToUpper
U+0395 U+03F5 pass: ToUpper
U+03D1 U+03F4 pass:
U+0398 U+03D1 pass: ToUpper
U+0398 U+03F4 pass:         ToLower
U+0345 U+1FBE pass: ToUpper
U+0345 U+0399 pass: ToUpper
U+0399 U+1FBE pass: ToUpper
U+039A U+03F0 pass: ToUpper
U+00B5 U+039C pass: ToUpper
U+03A0 U+03D6 pass: ToUpper
U+03A1 U+03F1 pass: ToUpper
U+03A3 U+03C2 pass: ToUpper
U+03A6 U+03D5 pass: ToUpper
U+03A9 U+2126 pass:         ToLower
U+0398 U+03F4 pass:         ToLower
U+03B8 U+03F4 pass:         ToLower
U+03B8 U+03D1 pass: ToUpper
U+0398 U+03D1 pass: ToUpper
U+0432 U+1C80 pass: ToUpper
U+0434 U+1C81 pass: ToUpper
U+043E U+1C82 pass: ToUpper
U+0441 U+1C83 pass: ToUpper
U+0442 U+1C84 pass: ToUpper
U+0442 U+1C85 pass: ToUpper
U+1C84 U+1C85 pass: ToUpper
U+044A U+1C86 pass: ToUpper
U+0412 U+1C80 pass: ToUpper
U+0414 U+1C81 pass: ToUpper
U+041E U+1C82 pass: ToUpper
U+0421 U+1C83 pass: ToUpper
U+1C84 U+1C85 pass: ToUpper
U+0422 U+1C84 pass: ToUpper
U+0422 U+1C85 pass: ToUpper
U+042A U+1C86 pass: ToUpper
U+0463 U+1C87 pass: ToUpper
U+0462 U+1C87 pass: ToUpper
upper pass: 46, lower pass: 8
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.