নিয়মিত অভিব্যক্তি সিনট্যাক্স ডিজাইনের দুর্বল পাঠযোগ্যতার কোনও নির্দিষ্ট কারণ আছে?


160

প্রোগ্রামাররা সকলেই সম্মত হন বলে মনে হয় যে কোডের পাঠযোগ্যতা শর্ট-সিনট্যাক্সড ওয়ান-লাইনারগুলির চেয়ে অনেক বেশি গুরুত্বপূর্ণ যা কাজ করে তবে কোনও সিনিয়র বিকাশকারীকে যে কোনও ডিগ্রির যথার্থতার সাথে ব্যাখ্যা করতে হয় - তবে এটি নিয়মিত অভিব্যক্তিগুলির ঠিক ঠিক নকশা করা হয়েছিল বলে মনে হয়। এর কি কোনও কারণ ছিল?

আমরা সকলেই একমত যে এর selfDocumentingMethodName()চেয়ে অনেক ভাল e()। কেন এটি নিয়মিত প্রকাশের ক্ষেত্রে প্রযোজ্য নয়?

আমার কাছে মনে হয় কোনও কাঠামোগত সংগঠন ছাড়াই এক-লাইন যুক্তির একটি বাক্য গঠন নকশা করার চেয়ে:

var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})(0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;

এবং এটি কোনও ইউআরএলকে কঠোরভাবে বিশ্লেষণও নয়!

পরিবর্তে, আমরা একটি বেসিক উদাহরণের জন্য কিছু পাইপলাইন কাঠামোটি সংগঠিত এবং পঠনযোগ্য করে তুলতে পারি:

string.regex
   .isRange('A-Z' || 'a-z')
   .followedBy('/r');

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


মন্তব্যগুলি বর্ধিত আলোচনার জন্য নয়; এই কথোপকথন চ্যাটে সরানো হয়েছে ।
ম্যাপেল_শ্যাফ্ট

1
আমি এই পাঠযোগ্যতার সমস্যাটি হুবহু রিজেক্সটুলবাক্স নামে একটি লাইব্রেরির সাথে মোকাবিলা করার চেষ্টা করেছি। এখনও পর্যন্ত এটি সি #, জাভা এবং জাভাস্ক্রিপ্টে পোর্ট করা হয়েছে - github.com/markwhitaker/RegexToolbox.CSharp দেখুন
মার্ক হুইটেকার

এই সমস্যাটি সমাধান করার জন্য অনেক চেষ্টা করা হয়েছে, তবে সংস্কৃতি পরিবর্তন করা শক্ত। মৌখিক প্রকাশ সম্পর্কে আমার উত্তর এখানে দেখুন । লোকেরা সর্বনিম্ন সাধারণ সরঞ্জামের জন্য পৌঁছায়।
পরিবার সরফ

উত্তর:


178

নিয়মিত এক্সপ্রেশনগুলি সংক্ষিপ্ত রূপ হিসাবে ডিজাইন করার একটি বড় কারণ রয়েছে: এগুলি কোড কোডের ভাষা হিসাবে নয়, কোড সম্পাদকের কমান্ড হিসাবে ব্যবহার করার জন্য ডিজাইন করা হয়েছিল More আরও স্পষ্টভাবে, edনিয়মিত এক্সপ্রেশন ব্যবহার করার প্রথম প্রোগ্রামগুলির মধ্যে একটি ছিল , এবং সেখান থেকে নিয়মিত প্রকাশগুলি বিশ্ব আধিপত্যের জন্য তাদের বিজয় শুরু করে। উদাহরণস্বরূপ, edকমান্ডটি g/<regular expression>/pশীঘ্রই একটি পৃথক প্রোগ্রাম নামক অনুপ্রেরণা জাগিয়ে তোলে grep, যা আজও ব্যবহৃত রয়েছে। তাদের শক্তির কারণে, তারা পরবর্তীকালে মানক হয়ে ওঠে sedএবং এর মতো বিভিন্ন সরঞ্জামে ব্যবহৃত হয়vim

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


5
রেজেক্সকে পার্স করার উদ্দেশ্যে নয়। অন্যথায়, স্ট্যাকওভারফ্লো . com / প্রশ্নগুলি / 1732348 /… 48 এবং মাথাব্যথা
njzk2

19
@ njzk2 এই উত্তরটি আসলে ভুল। এইচটিএমএল ডকুমেন্টটি কোনও নিয়মিত ভাষা নয়, তবে একটি এইচটিএমএল ওপেন ট্যাগ , যা প্রশ্নটি যা জিজ্ঞাসা করে তা আসলে।
র্যান্ডম 832

11
এটি মূল উত্তেজনাপত্রের মতো কেন রহস্যজনক তা ব্যাখ্যা করার একটি উত্তম উত্তর, তবে কেন বর্ধিত পাঠযোগ্যতার সাথে বর্তমানে বিকল্প বিকল্প নেই তা ব্যাখ্যা করে না।
ডক ব্রাউন

13
সুতরাং যারা চিন্তাভাবনাটি grepএকটি ভুল ব্যাখ্যা "দখল", এটা আসলে g/ re(নিয়মিত প্রকাশের জন্য) / থেকে আসে p?
হেগেন ভন ইটজেন

6
পুনঃটুইট করেছেন একটি উন্মুক্ত ট্যাগ ঠিক <aaa bbb="ccc" ddd='eee'>আছে, এর ভিতরে কোনও ট্যাগ নেইস্ট করা নেই। আপনি বাসা বাঁধতে পারবেন না, আপনি যা নীড় করেন সেগুলি হ'ল উপাদানগুলি (ওপেন ট্যাগ, শিশু উপাদান সহ সামগ্রী, নিকটবর্তী ট্যাগ), যা পার্সিংয়ের বিষয়ে প্রশ্ন করছিল না । এইচটিএমএল ট্যাগগুলি একটি নিয়মিত ভাষা - ভারসাম্য / বাসা বাঁধার উপরের ট্যাগগুলির স্তরে ঘটে at
র্যান্ডম 832

62

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

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

তা সত্ত্বেও, নিয়মিত প্রকাশগুলি প্রায়শই অতিরিক্ত ব্যবহার করা হয়, এটি অন্য কোনও সরঞ্জামের চেয়ে আরও ভাল applied আমি মনে করি না রেজেক্স সিনট্যাক্সটি ভয়াবহ । তবে এটি সংক্ষিপ্ত এবং সাধারণ নিদর্শনগুলিতে স্পষ্টভাবে আরও ভাল: সি-জাতীয় ভাষায় সনাক্তকারীগুলির প্রত্নতাত্ত্বিক উদাহরণটি [a-zA-Z_][a-zA-Z0-9_]*নিখুঁত ন্যূনতম জ্ঞানের সাথে পড়তে পারে এবং একবার এই বারটি মিলিত হওয়ার পরে এটি উভয়ই সুস্পষ্ট এবং সুন্দরভাবে সংহত হয়। কম অক্ষরের প্রয়োজন অন্তর্নিহিত খারাপ নয়, একেবারে বিপরীত। সংক্ষিপ্ত হওয়া একটি পুণ্য যদি আপনি বোধগম্য থাকেন provided

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

তাহলে কেন তারা আরও জটিল ক্ষেত্রে সংক্ষিপ্ত হয়ে পড়ে? আমি তিনটি প্রধান সমস্যা দেখতে পাচ্ছি:

  1. কোনও বিমূর্তকরণ ক্ষমতা নেই। সাধারণ ব্যাকরণগুলি, যা তাত্ত্বিক কম্পিউটার বিজ্ঞানের একই ক্ষেত্র থেকে রেজেক্সেস হিসাবে উত্পন্ন হয়, তার একটি সেট রয়েছে উত্পাদন, যাতে তারা প্যাটার্নের মধ্যবর্তী অংশগুলিকে নাম দিতে পারে:

    # This is not equivalent to the regex in the question
    # It's just a mock-up of what a grammar could look like
    url      ::= protocol? '/'? '/'? '/'? (domain_part '.')+ tld
    protocol ::= letter+ ':'
    ...
    
  2. যেমন আমরা উপরে দেখতে পেলাম, সাদা রঙের স্পেসিফিকেশনটির কোনও বিশেষ তাত্পর্য নেই যা ফর্ম্যাট করার অনুমতি দেয় যা চোখে সহজ। মন্তব্য সহ একই জিনিস। নিয়মিত এক্সপ্রেশনগুলি এটি করতে পারে না কারণ একটি স্থান কেবলমাত্র একটি আক্ষরিক ' '। যদিও দ্রষ্টব্য: কিছু বাস্তবায়ন একটি "ভার্বোস" মোডের অনুমতি দেয় যেখানে সাদা স্থান উপেক্ষা করা হয় এবং মন্তব্যগুলি সম্ভব হয়।

  3. সাধারণ নিদর্শন এবং সংযোজকগুলি বর্ণনা করার জন্য কোনও মেটা-ভাষা নেই। উদাহরণস্বরূপ, কেউ digitএকবার নিয়ম লিখতে এবং প্রসঙ্গে বিনামূল্যে ব্যাকরণে ব্যবহার করতে পারে, তবে কেউ "ফাংশন" সংজ্ঞায়িত করতে পারে না যাতে এমন কথা বলা যায় যে একটি উত্পাদন দেওয়া হয় pএবং একটি নতুন উত্পাদন তৈরি করে যা এর সাথে অতিরিক্ত কিছু করে, উদাহরণস্বরূপ তৈরি করুন সংঘটনগুলির একটি কমা দ্বারা বিচ্ছিন্ন তালিকার জন্য একটি উত্পাদন p

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

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

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


9
I don't know enough about the early years of computing to explain how regular expressions came to be so popular.আমরা যদিও অনুমানকে ঝুঁকি দিতে পারি: একটি বেসিক নিয়মিত এক্সপ্রেশন ইঞ্জিন কার্যকর করা খুব সহজ, একটি দক্ষ প্রসঙ্গ-মুক্ত পার্সারের তুলনায় অনেক সহজ।
বিজিক্লপ

15
@ বিজিক্লোপ আমি এই পরিবর্তনশীলটিকে বেশি গুরুত্ব দেবো না। ইয়্যাক, যার স্পষ্টতই যথেষ্ট পূর্বসূরি ছিল " এখনও অন্য একটি সংকলক সংকলক" হিসাবে পরিচিত, এটি 70 এর দশকের গোড়ার দিকে তৈরি হয়েছিল, এবং ইউনিক্সের আগে একটি সংস্করণ অন্তর্ভুক্ত grepহয়েছিল (সংস্করণ 3 বনাম সংস্করণ 4)। এটি প্রদর্শিত হয়

আমি কেবল উইকিপিডিয়ায় যা পেয়েছি তাতেই যেতে পারি (সুতরাং আমি এটি 100% বিশ্বাস করব না) তবে সেই অনুসারে, yacc1975 সালে এলএলআর পার্সারগুলির সম্পূর্ণ ধারণা তৈরি হয়েছিল (যা তাদের ব্যবহারিকভাবে ব্যবহারযোগ্য পার্সারদের প্রথম শ্রেণীর মধ্যে ছিল) ধরনের) এর সূত্রপাত ১৯ in৩ সালে। বন্ধ "। তবে আমি সন্দেহ করব যে একবার তাদের ব্যবহার করা টেক্সট এডিটর বিকাশকারীদের মধ্যে রাখলে তারা তাদের নিজের সফটওয়্যারটিতেও ব্যবহার করতে চেয়েছিল।
বাইজিক্লপ

1
@ jpmc26 তার বইটি জাভাস্ক্রিপ্ট দ্য গুড পার্টস টু রেগেক্স অধ্যায়টি খুলুন ।
ভিজিয়োনারি

2
with very few differences between dialectsআমি এটি "খুব কম" বলব না। যে কোনও পূর্বনির্ধারিত চরিত্র শ্রেণীর বিভিন্ন উপভাষার মধ্যে বেশ কয়েকটি সংজ্ঞা রয়েছে। এবং প্রতিটি উপভাষার জন্য নির্দিষ্ট পার্সিং quirks আছে।
nhahtdh

39

ঐতিহাসিক দৃষ্টিকোণ

উইকিপিডিয়া নিবন্ধটি নিয়মিত অভিব্যক্তির উত্স সম্পর্কে বেশ বিস্তারিতভাবে বর্ণনা করা হয়েছে (ক্লিন, 1956)। মূল সিনট্যাক্স শুধুমাত্র সঙ্গে তুলনামূলকভাবে সরল ছিল *, +, ?, |এবং গোষ্ঠী (...)। এটি ক্ষয়িষ্ণু ছিল ( এবং পাঠযোগ্য, দু'জনের পক্ষে প্রয়োজনীয় বিরোধিতা করা হয়নি), কারণ আনুষ্ঠানিক ভাষাগুলি গা .় গাণিতিক স্বরলিপি দিয়ে প্রকাশিত হয়।

পরবর্তীতে বাক্য গঠন এবং ক্ষমতা সম্পাদকদের সাথে বিকশিত হয় এবং পার্লের সাথে বৃদ্ধি পায় , যা নকশার সাহায্যে ক্ষয় করার চেষ্টা করা হয়েছিল ( "সাধারণ নির্মাণগুলি সংক্ষিপ্ত হওয়া উচিত" )। এটি সিনট্যাক্সকে অনেক জটিল করে তুলেছিল, তবে নোট করুন যে লোকেরা এখন নিয়মিত ভাবের সাথে অভ্যস্ত এবং সেগুলি লেখার ক্ষেত্রে (পড়তে না পারলে) ভাল। এগুলি যেহেতু তারা কখনও কখনও কেবল লেখার জন্য থাকে তা বোঝায় যে তারা যখন খুব দীর্ঘ হয় তবে সাধারণত তারা সঠিক সরঞ্জাম নয়। নিয়মিত প্রকাশগুলি অপব্যবহারযোগ্য হয়ে থাকে যখন অপব্যবহার করা হয়।

স্ট্রিং-ভিত্তিক নিয়মিত প্রকাশের বাইরে

বিকল্প বাক্য গঠন সম্পর্কে কথা বলুন, আসুন ইতিমধ্যে বিদ্যমান একটি ( কুল-পিপিসিয়ার , কমন লিস্পে ) এর এক ঝলক দেখি । আপনার দীর্ঘ নিয়মিত প্রকাশটি নীচের সাথে পার্স ppcre:parse-stringকরা যায়:

(let ((*print-case* :downcase)
      (*print-right-margin* 50))
  (pprint
   (ppcre:parse-string "^(?:([A-Za-z]+):)?(\\/{0,3})(0-9.\\-A-Za-z]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$")))

... এবং নিম্নলিখিত ফর্মের ফলাফল:

(:sequence :start-anchor
 (:greedy-repetition 0 1
  (:group
   (:sequence
    (:register
     (:greedy-repetition 1 nil
      (:char-class (:range #\A #\Z)
       (:range #\a #\z))))
    #\:)))
 (:register (:greedy-repetition 0 3 #\/))
 (:register
  (:sequence "0-9" :everything "-A-Za-z"
   (:greedy-repetition 1 nil #\])))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\:
    (:register
     (:greedy-repetition 1 nil :digit-class)))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\/
    (:register
     (:greedy-repetition 0 nil
      (:inverted-char-class #\? #\#))))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\?
    (:register
     (:greedy-repetition 0 nil
      (:inverted-char-class #\#))))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\#
    (:register
     (:greedy-repetition 0 nil :everything)))))
 :end-anchor)

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

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

`(:sequence
   :start-anchor
   ,(protocol)
   ,(slashes)
   ,(domain)
   ,(top-level-domain) ... )

স্ট্রিং-ভিত্তিক নিয়মিত এক্সপ্রেশনগুলিও স্ট্রিং কনটেনটেশন এবং বা সাহায্যকারী ফাংশনে মোড়ানো ইন্টারপোলেশন ব্যবহার করে রচনা করা যেতে পারে। যাইহোক, স্ট্রিং হেরফেরের সঙ্গে সীমাবদ্ধতা যা ঝোঁক হয় বিশৃঙ্খল কোড (পাখির সমস্যা, ব্যাকটিক অসদৃশ বনাম না আমার মনে হয় $(...)ব্যাশ হয়; এছাড়াও, অব্যাহতি আপনি যে অক্ষরগুলি মাথাব্যাথা দিতে পারে)।

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

শেষ করা

  • বেশিরভাগ উদ্দেশ্যে, সংক্ষেপে স্বরলিপিটি আসলে পাঠযোগ্য। ব্যাকট্র্যাকিং ইত্যাদি জড়িত বর্ধিত স্বরলিপিগুলি নিয়ে কাজ করার সময় অসুবিধা রয়েছে, তবে তাদের ব্যবহার খুব কমই ন্যায়সঙ্গত হয়। নিয়মিত এক্সপ্রেশনগুলির অনিয়ন্ত্রিত ব্যবহার অপঠনযোগ্য প্রকাশ করতে পারে lead

  • নিয়মিত এক্সপ্রেশনগুলি স্ট্রিং হিসাবে এনকোড করা দরকার না। আপনার কাছে যদি কোনও লাইব্রেরি বা একটি সরঞ্জাম রয়েছে যা আপনাকে নিয়মিত এক্সপ্রেশন তৈরি করতে এবং রচনা করতে সহায়তা করে, আপনি স্ট্রিং ম্যানিপুলেশন সম্পর্কিত অনেকগুলি সম্ভাব্য বাগগুলি এড়াতে পারবেন ।

  • বিকল্পভাবে, আনুষ্ঠানিক ব্যাকরণগুলি আরও পঠনযোগ্য এবং উপ-এক্সপ্রেশনগুলির নামকরণ এবং বিমূর্তকরণে আরও ভাল। টার্মিনালগুলি সাধারণত সাধারণ নিয়মিত এক্সপ্রেশন হিসাবে প্রকাশ করা হয়।


১. আপনি পঠনের সময় আপনার অভিব্যক্তি তৈরি করতে পছন্দ করতে পারেন, কারণ নিয়মিত প্রকাশগুলি কোনও অ্যাপ্লিকেশনটিতে ধ্রুবক হিসাবে থাকে। দেখুন create-scannerএবং load-time-value:

'(:sequence :start-anchor #.(protocol) #.(slashes) ... )

5
হতে পারে আমি কেবল traditionalতিহ্যবাহী রেজেক্সেক্স সিনট্যাক্সে অভ্যস্ত, তবে আমি এতটা নিশ্চিত নই যে সমতুল্য এক লাইন রেজেক্সের চেয়ে 22 কিছুটা পঠনযোগ্য লাইন বোঝা সহজ।

3
@ dan1111 "কিছুটা পাঠযোগ্য" ;-) ঠিক আছে, কিন্তু যদি আপনি সত্যিই একটি দীর্ঘ Regex থাকতে হবে, এটা জ্ঞান সাব-সেট নির্বাচন, মত সংজ্ঞায়িত করে তোলে digits, identএবং তাদেরকে রচনা। আমি যেভাবে দেখছি এটি সাধারণত স্ট্রিং ম্যানিপুলেশনগুলি (কনটেন্টেশন বা ইন্টারপোলেশন) দিয়ে থাকে যা সঠিকভাবে পালানোর মতো অন্যান্য সমস্যা নিয়ে আসে। \\\\`উদাহরণস্বরূপ, ইমাস প্যাকেজগুলিতে উপস্থিতিগুলি অনুসন্ধান করুন । BTW, এই খারাপ তৈরি করা হয় কারণ একই এস্কেপ অক্ষর উভয় মত বিশেষ অক্ষর ব্যবহার করা হয় \nএবং \"এবং Regex সিনট্যাক্স জন্য \(। ভাল সিনট্যাক্সের একটি নন-লিস্প উদাহরণ printf, যেখানে %dদ্বন্দ্ব নেই \d
বিরক্তিকর

1
সংজ্ঞায়িত উপসেটগুলি সম্পর্কে সুস্পষ্ট পয়েন্ট। ওটা অনেক কিছু প্রকাশ করে. আমি কেবল সংশয়বাদী যে শব্দটির এক উন্নতি। এটি প্রাথমিকভাবে সহজ হতে পারে (যদিও মত ধারণাগুলি greedy-repetitionস্বজ্ঞাত নয় এবং এখনও শিখতে হবে)। তবে এটি বিশেষজ্ঞদের পক্ষে ব্যবহারের যোগ্যতা ত্যাগ করে, যেহেতু পুরো প্যাটার্নটি দেখা এবং উপলব্ধি করা আরও কঠিন।

@ dan1111 আমি সম্মত হলাম যে নিজে থেকেই ভার্বোসটি কোনও উন্নতি নয়। স্ট্রিংগুলির পরিবর্তে স্ট্রাকচার্ড ডেটা ব্যবহার করে রেজেক্সে ম্যানিপুলেট করা যা উন্নতি হতে পারে তা What
coredump

@ dan1111 সম্ভবত আমার হাস্কেল ব্যবহার করে কোনও সম্পাদনার প্রস্তাব দেওয়া উচিত? পার্সেক এটি কেবল নয়টি লাইনে করে; একটি এক মাছ ধরার নৌকা হিসাবে: do {optional (many1 (letter) >> char ':'); choice (map string ["///","//","/",""]); many1 (oneOf "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-."); optional (char ':' >> many1 digit); optional (char '/' >> many (noneOf "?#")); optional (char '?' >> many (noneOf "#")); optional (char '#' >> many (noneOf "\n")); eof}। লম্বা স্ট্রিংটিকে যেমন নির্ধারণ করার মতো কয়েকটি লাইন domainChars = ...এবং section start p = optional (char start >> many p)এটি দেখতে বেশ সহজ দেখাচ্ছে।
সিআর ড্রস্ট 16

25

রেজেক্সের সবচেয়ে বড় সমস্যা অত্যধিক সংশ্লেষ সিনট্যাক্স নয়, ছোট বিল্ডিং ব্লকগুলি থেকে এটি রচনা না করে আমরা একক অভিব্যক্তিতে একটি জটিল সংজ্ঞা প্রকাশ করার চেষ্টা করি। এটি প্রোগ্রামিংয়ের মতো যেখানে আপনি কখনই ভেরিয়েবল এবং ফাংশন ব্যবহার করবেন না এবং পরিবর্তে আপনার কোডটি সমস্ত একক লাইনে এম্বেড করুন।

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

উদাহরণস্বরূপ rfc3986 এ ইউআরআই সিনট্যাক্সটি দেখুন :

URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
hier-part     = "//" authority path-abempty
              / path-absolute
              / path-rootless
              / path-empty
...

আপনি রেগেক্স সিনট্যাক্সের বৈকল্পিক ব্যবহার করে প্রায় একই জিনিস লিখতে পারেন যা নামযুক্ত সাব-এক্সপ্রেশনগুলি এম্বেডিং সমর্থন করে।


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


12

#DocamentingMethodName () ই () এর চেয়ে অনেক ভাল

তাই কি? বেশিরভাগ ভাষায় বিগিন এবং সমাপ্তির পরিবর্তে ব্লক ডিলিমিটার হিসাবে {এবং} থাকার একটি কারণ রয়েছে।

লোকেরা তীক্ষ্ণতা পছন্দ করে এবং সিন্টেক্সটি একবার জানলে সংক্ষিপ্ত পরিভাষা আরও ভাল। আপনার রেজেক্স উদাহরণটি কল্পনা করুন যদি ডি (অঙ্কের জন্য) 'ডিজিট' হত তবে রেজেক্স আরও পড়ার জন্য আরও ভয়াবহ হবে। আপনি যদি এটিকে নিয়ন্ত্রণের অক্ষরগুলির সাথে আরও সহজেই পার্সেবল করতে সক্ষম করেন তবে এটি আরও XML এর মতো দেখতে look আপনি সিনট্যাক্সটি একবার জানলে তত ভাল হয় না।

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


1
selfDocumentingMethodNameহয় সাধারণত একমত তুলনায় ভালো হবে বলে eকারণ প্রোগ্রামার স্বজ্ঞা সঙ্গে লাইন আপ না আসলে পাঠযোগ্যতা বা ভাল মানের কোড গঠন পরিপ্রেক্ষিতে বাস্তবতা । সম্মত হওয়া লোকেরা ভুল, তবে এটি এটি।
লিউশেনকো

1
@ লুশেনকো: আপনি কি দাবি করছেন যে এর e()চেয়ে ভাল selfDocumentingMethodName()?
জ্যাকবিবি

3
@ জ্যাক্কসবি সম্ভবত সমস্ত প্রসঙ্গে নয় (বিশ্বব্যাপী নামের মতো)। তবে আঁটসাঁট জিনিসগুলির জন্য? প্রায় অবশ্যই. প্রচলিত জ্ঞান যা বলে তার চেয়ে বেশি প্রায়ই।
লুশেনকো

1
@ লুশেনকো: প্রসঙ্গটি কল্পনা করতে আমার খুব কষ্ট হয়েছে যে একটি বর্ণের ফাংশন নামটি আরও বর্ণনামূলক নামের চেয়ে ভাল। তবে আমার ধারণা এটি খাঁটি মতামত।
জ্যাকবিবি

1
@ মাইলসআরআউট: উদাহরণটি e()একটি স্ব ডকুমেন্টিং পদ্ধতির নাম বনামের জন্য । বর্ণনামূলক পদ্ধতির নামের পরিবর্তে একক-বর্ণের নাম ব্যবহার করা কোন প্রসঙ্গে আপনি ব্যাখ্যা করতে পারেন?
জ্যাকবি 10

6

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

রেজেক্স লেগো টুকরাগুলির মতো। কয়েকটি যুক্তি রয়েছে যা ব্যবহার করা যেতে পারে তবে তাদের বিভিন্ন আকারে শৃঙ্খলাবদ্ধ করে তোলা কয়েক মিলিয়ন বিভিন্ন রেইগেক্স নিদর্শন তৈরি করে যা অনেক জটিল কাজের জন্য ব্যবহার করা যেতে পারে।

লোকেরা একাই খুব কমই রেজেক্স প্যারামিটার ব্যবহার করে। অনেকগুলি ভাষা আপনাকে স্ট্রিংয়ের দৈর্ঘ্য যাচাই বা সংখ্যার অংশগুলি এর বাইরে ভাগ করার জন্য ফাংশন দেয়। আপনি পাঠ্য টুকরো টুকরো করতে এবং তাদের সংশোধন করতে স্ট্রিং ফাংশন ব্যবহার করতে পারেন। যখন আপনি খুব নির্দিষ্ট জটিল কাজগুলি করার জন্য জটিল ফর্মগুলি ব্যবহার করেন তখন রেজেক্সের শক্তি লক্ষ্য করা যায়।

আপনি এসওতে কয়েক হাজার রিজেক্স প্রশ্ন খুঁজে পেতে পারেন এবং এগুলি খুব কমই নকল হিসাবে চিহ্নিত হয়েছে। এটি একাই সম্ভাব্য অনন্য ব্যবহারের কেসগুলি দেখায় যা একে অপরের থেকে খুব আলাদা।

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


2

আমি বুঝতে পারছি এটি শক্তি প্রয়োগের চেয়ে অনুশীলনের সমস্যা। সমস্যাটি দেখা দেয় যখন নিয়মিত প্রকাশগুলি সরাসরি প্রয়োগ করা হয়, পরিবর্তে সম্মিলিত প্রকৃতি ধরে না নেওয়া। একইভাবে, একটি ভাল প্রোগ্রামার সংক্ষিপ্ত পদ্ধতিতে তার প্রোগ্রামের কার্যগুলি ক্ষয় করবে।

উদাহরণস্বরূপ, একটি ইউআরএল জন্য একটি রেজেক্স স্ট্রিং প্রায় থেকে হ্রাস করা যেতে পারে:

UriRe = [scheme][hier-part][query][fragment]

প্রতি:

UriRe = UriSchemeRe + UriHierRe + "(/?|/" + UriQueryRe + UriFragRe + ")"
UriSchemeRe = [scheme]
UriHierRe = [hier-part]
UriQueryRe = [query]
UriFragRe = [fragment]

নিয়মিত প্রকাশগুলি তাত্পর্যপূর্ণ জিনিস, তবে তাদের আপত্তিজনক জটিলতায় ডুবে যাওয়া লোকেরা তাদের দ্বারা নির্যাতনের ঝুঁকিতে থাকে । ফলস্বরূপ প্রকাশগুলি বাকবাণী, দীর্ঘমেয়াদী মূল্য অনুপস্থিত are


2
দুর্ভাগ্যক্রমে বেশিরভাগ প্রোগ্রামিং ভাষাগুলিতে এমন কার্যকারিতা অন্তর্ভুক্ত থাকে না যা রাইজেক্সগুলি রচনায় সহায়তা করে এবং গ্রুপ ক্যাপচার কাজটি রচনার পক্ষে খুব বন্ধুত্বপূর্ণ নয়।
কোডসইনচাউস

1
অন্যান্য ভাষার তাদের "পার্ল সামঞ্জস্যপূর্ণ নিয়মিত প্রকাশ" সমর্থনে পার্ল 5 পর্যন্ত ধরা দরকার catch Subexpressions কেবল রেগেক্স স্পেসিফিকেশনের স্ট্রাকটেনটিং স্ট্রিংয়ের সমান নয়। ক্যাপচারগুলির নাম দেওয়া উচিত, অন্তর্নিহিত সংখ্যার উপর নির্ভর করে না।
JDługosz

0

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

পার্ল হোয়াইট স্পেস এবং মন্তব্যের অনুমতি দিয়ে তাদের আরও পঠনযোগ্য করে তোলার ক্ষেত্রে বরং একটি দুর্বল প্রচেষ্টা করে তবে দূর থেকে কল্পনাপ্রসূত কিছু করে না।

অন্যান্য বাক্য গঠন রয়েছে। একটি ভাল হ'ল রিজেক্সপ্সের জন্য স্ক্যাশ সিনট্যাক্স , যা আমার অভিজ্ঞতা অনুসারে রিজেক্সপস তৈরি করে যা টাইপ করা সহজ, তবে সত্যের পরেও পঠনযোগ্য।

[ অন্যান্য কারণে স্ক্যাশ জাঁকজমকপূর্ণ, যার মধ্যে একটি এর বিখ্যাত স্বীকৃতি পাঠ্য ]


2
পার্ল 6 করে! ব্যাকরণ তাকান।
JDługosz

@ জেডিগোগোস যতদূর আমি দেখতে পাচ্ছি, এটি নিয়মিত প্রকাশের বিকল্প বিকল্প বাক্য গঠনের চেয়ে পার্সার জেনারেটরগুলির জন্য আরও একটি পদ্ধতির মতো দেখায়। তবে পার্থক্যটি সম্ভবত খুব গভীর নয়।
নরম্যান গ্রে

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

0

আমি বিশ্বাস করি যে নিয়মিত-এক্সপ্রেশনগুলি 'সাধারণ' এবং যথাসম্ভব সাধারণ হিসাবে নকশাকৃত করা হয়েছিল, যাতে এগুলি যে কোনও জায়গায় (প্রায়) একইভাবে ব্যবহার করা যায়।

আপনি উদাহরণস্বরূপ regex.isRange(..).followedBy(..)একটি নির্দিষ্ট প্রোগ্রামিং ভাষার সিনট্যাক্স এবং সম্ভবত অবজেক্ট-ওরিয়েন্টেড স্টাইল (পদ্ধতির শৃঙ্খলা) উভয়ের সাথে মিলিত।

উদাহরণস্বরূপ এই সঠিক 'রেজেক্স' কে কীভাবে দেখাবে? কোডটি পরিবর্তন করতে হবে।

সর্বাধিক 'সাধারণ' পদ্ধতির মধ্যে একটি সরল সংক্ষিপ্ত ভাষা সংজ্ঞায়িত করা হবে যা পরে পরিবর্তন ছাড়াই অন্য কোনও ভাষায় সহজেই এম্বেড করা যেতে পারে। এবং এটি (প্রায়) রেজেেক্স কি what


0

পার্ল-সামঞ্জস্যপূর্ণ নিয়মিত এক্সপ্রেশন ইঞ্জিনগুলি ব্যাপকভাবে ব্যবহৃত হয়, একটি সংক্ষিপ্ত নিয়মিত এক্সপ্রেশন সিনট্যাক্স সরবরাহ করে যা অনেক সম্পাদক এবং ভাষা বোঝে। @ জেডিগুগোস মন্তব্যগুলিতে যেমন উল্লেখ করেছেন, পার্ল 6 (পার্ল 5 এর একটি নতুন সংস্করণ নয়, সম্পূর্ণ আলাদা ভাষা) স্বতন্ত্র-সংজ্ঞায়িত উপাদানগুলি থেকে তাদের তৈরি করে নিয়মিত প্রকাশগুলি আরও পাঠযোগ্য করে তোলার চেষ্টা করেছে। উদাহরণস্বরূপ, এখানে উইকিউবুকগুলি থেকে ইউআরএল পার্স করার জন্য ব্যাকরণ একটি উদাহরণ :

grammar URL {
  rule TOP {
    <protocol>'://'<address>
  }
  token protocol {
    'http'|'https'|'ftp'|'file'
  }
  rule address {
    <subdomain>'.'<domain>'.'<tld>
  }
  ...
}

এর মতো নিয়মিত অভিব্যক্তি বিভক্ত করা প্রতিটি বিটকে স্বতন্ত্রভাবে সংজ্ঞায়িত করতে দেয় (উদাহরণস্বরূপ domainবর্ণানুক্রমিক হতে বাধ্য ) বা সাবক্লাসিংয়ের মাধ্যমে প্রসারিত (যেমন কেবলমাত্র FileURL is URLসীমাবদ্ধতা )।protocol"file"

সুতরাং: না, নিয়মিত অভিব্যক্তিগুলির সংক্ষিপ্ততার কোনও প্রযুক্তিগত কারণ নেই, তবে তাদের উপস্থাপনের জন্য আরও নতুন, ক্লিনার এবং আরও পঠনযোগ্য উপায়গুলি ইতিমধ্যে এখানে রয়েছে! সুতরাং আশা করি আমরা এই ক্ষেত্রে কিছু নতুন ধারণা দেখতে পাবেন।

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