ব্রেভিটি বনাম পঠনযোগ্যতা: একটি মধ্য গ্রাউন্ড
যেমনটি আপনি দেখেছেন, এই সমস্যাটি এমন সমাধানগুলিকে স্বীকৃতি দেয় যা মাঝারিভাবে দীর্ঘ এবং কিছুটা পুনরাবৃত্তিযোগ্য তবে অত্যন্ত পঠনযোগ্য ( টেরডন এবং এবি এর বাশ উত্তর), সেইসাথে যেগুলি খুব স্বল্প কিন্তু স্বজ্ঞাত এবং অনেক কম স্ব-দলিলকরণ (টিমের অজগর) এবং ব্যাশ উত্তর এবং গ্লেন জ্যাকম্যানের পার্ল উত্তর )। এই সমস্ত পদ্ধতির মূল্যবান।
কমপ্যাক্টনেস এবং পঠনযোগ্যতার মধ্যে ধারাবাহিকতার মাঝখানে আপনি কোড সহ এই সমস্যাটিও সমাধান করতে পারেন। এই পদ্ধতির প্রায় দীর্ঘ সমাধান হিসাবে প্রায় পঠনযোগ্য, ছোট, রহস্য সমাধানের দৈর্ঘ্য কাছাকাছি।
#!/usr/bin/env bash
read -erp 'Enter numeric grade (q to quit): '
case $REPLY in [qQ]) exit;; esac
declare -A cutoffs
cutoffs[F]=59 cutoffs[D]=69 cutoffs[C]=79 cutoffs[B]=89 cutoffs[A]=100
for letter in F D C B A; do
((REPLY <= cutoffs[$letter])) && { echo $letter; exit; }
done
echo "Grade out of range."
এই ব্যাশ সমাধানে, পাঠযোগ্যতা বাড়ানোর জন্য আমি কয়েকটি ফাঁকা লাইন অন্তর্ভুক্ত করেছি, তবে আপনি যদি এটি আরও ছোট করতে চান তবে আপনি সেগুলি সরিয়ে ফেলতে পারেন।
ফাঁকা লাইনগুলি অন্তর্ভুক্ত রয়েছে, এটি আসলে একটি কমপ্যাক্টিফাইডের তুলনায় কেবল সামান্য খাটো , এ বি এর বাশ সমাধানের এখনও বেশ সুন্দর পঠনযোগ্য বৈকল্পিক । এই পদ্ধতির উপর এটির প্রধান সুবিধাগুলি হ'ল:
- এটি আরও স্বজ্ঞাত।
- গ্রেডগুলির মধ্যে সীমানা পরিবর্তন করা (বা অতিরিক্ত গ্রেড যুক্ত করা) সহজ।
- এটি স্বয়ংক্রিয়ভাবে নেতৃস্থানীয় এবং অনুসরণযোগ্য স্পেসগুলির সাথে ইনপুট গ্রহণ করে (কীভাবে
((
))
কাজ করে তার একটি ব্যাখ্যার জন্য নীচে দেখুন )।
এই তিনটি সুবিধাই উত্থাপিত হয় কারণ এই পদ্ধতিটি ব্যবহারকারীর ইনপুটটিকে সংবিধানের অঙ্কগুলি ম্যানুয়ালি পরীক্ষার পরিবর্তে সংখ্যাগত ডেটা হিসাবে ব্যবহার করে।
কিভাবে এটা কাজ করে
- ব্যবহারকারীর কাছ থেকে ইনপুট পড়ুন। তারা প্রবেশ করানো পাঠ্যে (
-e
) প্রবেশ করিয়ে তীরচিহ্নগুলি ব্যবহার করতে দিন এবং \
একটি পালানোর চরিত্র হিসাবে ব্যাখ্যা করবেন না ( -r
)।
এই স্ক্রিপ্টটি কোনও বৈশিষ্ট্য সমৃদ্ধ সমাধান নয় - সংশোধন করার জন্য নীচে দেখুন - তবে এই দরকারী বৈশিষ্ট্যগুলি কেবল এটি দুটি অক্ষরকে আরও দীর্ঘায়িত করে। আমি সবসময় ব্যবহার করার প্রস্তাব -r
দিয়ে read
, যদি না আপনি জানেন আপনি ব্যবহারকারীর সরবরাহ জানানোর প্রয়োজন বোধ করি \
পালাতে।
- যদি ব্যবহারকারী লিখে থাকেন
q
বা Q
, ছেড়ে দিন।
- একটি সহযোগী অ্যারে (
declare -A
) তৈরি করুন । প্রতিটি অক্ষরের গ্রেডের সাথে সম্পর্কিত সর্বোচ্চ সংখ্যাসূচক গ্রেডের সাথে এটিকে আস্তরণ করুন।
- লেটার গ্রেডগুলি সর্বনিম্ন থেকে সর্বোচ্চে লুপ করুন , ব্যবহারকারী-প্রদত্ত সংখ্যাটি প্রতিটি বর্ণের গ্রেডের সংখ্যার পরিসরে পড়ার মতো যথেষ্ট কম কিনা তা পরীক্ষা করে।
সঙ্গে ((
))
গাণিতিক মূল্যায়ন পরিবর্তনশীল নামের সাথে প্রসারিত করা প্রয়োজন হবে না $
। (বেশিরভাগ অন্যান্য পরিস্থিতিতে আপনি যদি তার নামের পরিবর্তে কোনও ভেরিয়েবলের মান ব্যবহার করতে চান তবে আপনাকে এটি করতে হবে ))
- এটি যদি সীমার মধ্যে পড়ে তবে গ্রেডটি প্রিন্ট করুন এবং প্রস্থান করুন ।
সংক্ষিপ্ততা জন্য, আমি শর্ট সার্কিট ব্যবহার এবং অপারেটর ( &&
বরং একটি তুলনায়) if
- then
।
- যদি লুপটি শেষ হয়ে যায় এবং কোনও ব্যাপ্তি মিলে না যায় তবে অনুমান করা সংখ্যাটি খুব বেশি (100 এরও বেশি) এবং ব্যবহারকারীকে বলুন যে এটির সীমার বাইরে ছিল।
অদ্ভুত ইনপুট সহ এটি কীভাবে আচরণ করে
পোস্ট করা অন্যান্য সংক্ষিপ্ত সমাধানগুলির মতো , এই স্ক্রিপ্টটি কোনও সংখ্যা অনুমান করার আগে ইনপুটটি পরীক্ষা করে না। পাটিগণিত মূল্যায়ন ( ((
))
) স্বয়ংক্রিয়ভাবে সামনের এবং হোয়াইটস্পেস trailing পটির, তাই যে কোন সমস্যা নেই, কিন্তু:
- যে সংখ্যার মোটেও দেখতে পঠিত নয় এমন ইনপুট 0 হিসাবে ব্যাখ্যা করা হয়।
- ইনপুট সহ যা সংখ্যার মতো দেখাচ্ছে (যেমন এটি যদি একটি অঙ্ক দিয়ে শুরু হয়) তবে এতে অবৈধ অক্ষর রয়েছে, স্ক্রিপ্টটি ত্রুটিগুলি নির্গত করে।
- মাল্টি অঙ্ক ইনপুট দিয়ে শুরু
0
হয় হচ্ছে হিসেবে ব্যাখ্যা মধ্যে অকট্যাল । উদাহরণস্বরূপ, স্ক্রিপ্টটি আপনাকে 77 ডিগ্রি সেন্টিগ্রেড বলে দেবে, যখন 077 ডি একটি ডি যদিও কিছু ব্যবহারকারী এটি চাইতে পারে তবে সম্ভবত এটি না এবং এটি বিভ্রান্তির কারণ হতে পারে।
- প্লাস দিকে, যখন একটি গাণিতিক এক্সপ্রেশন দেওয়া হয়, এই স্ক্রিপ্টটি স্বয়ংক্রিয়ভাবে এটিকে সরল করে এবং সম্পর্কিত চিঠি গ্রেড নির্ধারণ করে। উদাহরণস্বরূপ, এটি আপনাকে বলবে 320/4 একটি বি।
একটি প্রসারিত, সম্পূর্ণ বৈশিষ্ট্যযুক্ত সংস্করণ
এই কারণগুলির জন্য, আপনি এই প্রসারিত স্ক্রিপ্টের মতো কিছু ব্যবহার করতে চাইতে পারেন, যা ইনপুটটি ভাল তা নিশ্চিত করার জন্য পরীক্ষা করে এবং এতে আরও কিছু বর্ধন রয়েছে।
#!/usr/bin/env bash
shopt -s extglob
declare -A cutoffs
cutoffs[F]=59 cutoffs[D]=69 cutoffs[C]=79 cutoffs[B]=89 cutoffs[A]=100
while read -erp 'Enter numeric grade (q to quit): '; do
case $REPLY in # allow leading/trailing spaces, but not octal (e.g. "03")
*( )@([1-9]*([0-9])|+(0))*( )) ;;
*( )[qQ]?([uU][iI][tT])*( )) exit;;
*) echo "I don't understand that number."; continue;;
esac
for letter in F D C B A; do
((REPLY <= cutoffs[$letter])) && { echo $letter; continue 2; }
done
echo "Grade out of range."
done
এটি এখনও একটি বেশ কমপ্যাক্ট সমাধান।
এটি কোন বৈশিষ্ট্যগুলি যুক্ত করে?
এই প্রসারিত স্ক্রিপ্টের মূল বিষয়গুলি হ'ল:
- ইনপুট বৈধতা। টেরডনের স্ক্রিপ্টটি ইনপুটটি চেক করে , তাই আমি অন্য একটি উপায় দেখায়, যা কিছু সংক্ষিপ্ততাকে ত্যাগ করে তবে আরও দৃust় হয় , ব্যবহারকারীকে নেতৃত্বাধীন এবং অনুসরণ করার জায়গাগুলিতে প্রবেশ করতে দেয় এবং অ্যাক্টাল হিসাবে অভিহিত বা নাও হতে পারে এমন অভিব্যক্তিটিকে অনুমতি দিতে অস্বীকার করে (এটি শূন্য না হলে) ।
if [[ ! $response =~ ^[0-9]*$ ]] ...
- আমি ব্যবহার করেছি
case
সঙ্গে globbing বর্ধিত পরিবর্তে [[
সঙ্গে =~
রেগুলার এক্সপ্রেশন ম্যাচিং (হিসাবে অপারেটর terdon এর উত্তর )। এটি (এবং কীভাবে) এটিও সেইভাবে করা যেতে পারে তা দেখানোর জন্য আমি এটি করেছি। গ্লোবস এবং রিজেক্সপস হ'ল পাঠ্যগুলির সাথে মেলে এমন নিদর্শনগুলি নির্দিষ্ট করার দুটি উপায় এবং এই অ্যাপ্লিকেশনটির জন্য দুটি পদ্ধতিই ভাল।
- এবি বাশ স্ক্রিপ্টের মতো , আমি পুরো জিনিসটি একটি বাহ্যিক লুপে আবদ্ধ করে রেখেছি (
cutoffs
অ্যারের প্রাথমিক তৈরি ব্যতীত )। এটি সংখ্যার জন্য অনুরোধ করে এবং যতক্ষণ না টার্মিনাল ইনপুট উপলব্ধ থাকে এবং ব্যবহারকারী এটি ছাড়তে বলেনি ততক্ষণ সংশ্লিষ্ট চিঠি গ্রেড দেয়। আপনার প্রশ্নের কোডটির চারপাশে do
... বিচার করে done
দেখে মনে হচ্ছে আপনি এটি চান that
- সহজ প্রস্থান করার জন্য, আমি কোন কেস-অবশ বৈকল্পিক গ্রহণ
q
বা quit
।
এই স্ক্রিপ্টটিতে কয়েকটি কনস্ট্রাক্ট ব্যবহার করা হয়েছে যা নবীনদের সাথে অপরিচিত হতে পারে; তারা নীচে বিস্তারিত।
ব্যাখ্যা: ব্যবহার continue
আমি যখন বাইরের while
লুপের বাকী শরীরের উপর দিয়ে যেতে চাই, তখন আমি continue
কমান্ডটি ব্যবহার করি । আরও ইনপুট পড়তে এবং অন্য পুনরাবৃত্তি চালানোর জন্য এটি এটিকে আবার লুপের শীর্ষে নিয়ে আসে।
প্রথমবার আমি এটিটি করার পরে, আমি কেবলমাত্র লুপটি আছি বাহ্যিক while
লুপ, সুতরাং আমি continue
কোনও যুক্তি ছাড়াই কল করতে পারি । (আমি একটি case
নির্মাণে আছি , তবে এটি break
বা এর কাজকর্মকে প্রভাবিত করে না continue
))
*) echo "I don't understand that number."; continue;;
তবে দ্বিতীয়বার, আমি একটি অভ্যন্তরীণ for
লুপে আছি যা নিজেই বাহ্যিক while
লুপের ভিতরে বাসা বাঁধে। যদি আমি continue
কোনও যুক্তি না দিয়ে ব্যবহার করি তবে এটি সমতুল্য হবে continue 1
এবং for
বাইরের while
লুপের পরিবর্তে অভ্যন্তরীণ লুপটি চালিয়ে যাবে ।
((REPLY <= cutoffs[$letter])) && { echo $letter; continue 2; }
সুতরাং সেই ক্ষেত্রে আমি continue 2
ব্যাশ সন্ধান করতে এবং পরিবর্তে দ্বিতীয় লুপটি চালিয়ে যেতে ব্যবহার করি।
ব্যাখ্যা: case
গ্লোব সহ লেবেল
case
কোন লেটার গ্রেড বিন কোন সংখ্যায় পড়ে তা নির্ধারণ করার জন্য আমি ব্যবহার করি না (যেমন এবি এর বাশ উত্তরে )। তবে case
ব্যবহারকারীর ইনপুটটি বিবেচনা করা উচিত কিনা তা সিদ্ধান্ত নিতে আমি ব্যবহার করি :
- একটি বৈধ সংখ্যা,
*( )@([1-9]*([0-9])|+(0))*( )
- ছাড়ার আদেশ,
*( )[qQ]?([uU][iI][tT])*( )
- অন্য কিছু (এবং এইভাবে অবৈধ ইনপুট),
*
এগুলি শেল গ্লোবস ।
- প্রত্যেকটি এর পরে একটি
)
খোলার সাথে মিলে যায় না (
যা মিল হয় case
যখন চালানো কমান্ডগুলি থেকে কোনও প্যাটার্নকে আলাদা করার জন্য সিনট্যাক্স।
;;
হয় case
একটি paticular ক্ষেত্রে ম্যাচের জন্য চালানোর জন্য (এবং কোনো পরবর্তী মামলা তাদের চলমান পরে পরীক্ষা করা উচিত) কমান্ড শেষে ইঙ্গিত 's সিনট্যাক্স।
সাধারণ শেল গ্লোব্বিং *
শূন্য বা আরও বেশি অক্ষরের ?
সাথে মিল রাখতে, ঠিক একটি অক্ষরের সাথে এবং [
]
ব্র্যাকেটে অক্ষরের শ্রেণি / ব্যাপ্তি সরবরাহ করে । তবে আমি বর্ধিত গ্লোব্বিং ব্যবহার করছি , যা এর বাইরে চলে যায়। bash
ইন্টারেক্টিভভাবে ব্যবহার করার সময় বর্ধিত গ্লোববিং ডিফল্টরূপে সক্ষম হয় তবে স্ক্রিপ্ট চালানোর সময় ডিফল্টরূপে অক্ষম থাকে। shopt -s extglob
স্ক্রিপ্ট উপরের কমান্ড এটা চালু করে।
ব্যাখ্যা: বর্ধিত গ্লোব্বিং
*( )@([1-9]*([0-9])|+(0))*( )
, যা সংখ্যার ইনপুট জন্য পরীক্ষা করে এটি একটি ক্রমের সাথে মেলে:
- শূন্য বা আরও বেশি স্থান (
*( )
)। *(
)
কনস্ট্রাক্ট ম্যাচ শূন্য বা বন্ধনীর মধ্যে প্যাটার্ন, শুধু একটি স্থান এখানে যার আরও অনেক কিছু।
প্রকৃতপক্ষে দুই ধরণের অনুভূমিক সাদা স্থান, স্থান এবং ট্যাব রয়েছে এবং প্রায়শই এটি ট্যাবগুলিও মেলাতে পছন্দনীয়। তবে আমি এখানে এটি নিয়ে উদ্বিগ্ন হচ্ছি না, কারণ এই স্ক্রিপ্টটি ম্যানুয়াল, ইন্টারেক্টিভ ইনপুট এবং জিএনইউ পাঠ্যরেখাকে সক্ষম -e
করার জন্য পতাকাটির জন্য লেখা হয়েছে read
। এটি তাই বাম এবং ডান তীরচিহ্নগুলি সহ ব্যবহারকারী তাদের পাঠ্যে পিছনে পিছনে সরে যেতে পারে তবে এটির ট্যাবগুলিকে আক্ষরিকভাবে প্রবেশ করা থেকে বিরত করার পার্শ্ব প্রতিক্রিয়া রয়েছে।
@(
)
উভয়ের ( |
) এর একটি ঘটনা ( ):
- একটি ননজারো ডিজিট (
[1-9]
) এর পরে শূন্য বা *(
)
যেকোন অঙ্কের ( [0-9]
) বেশি ( )।
- এক বা একাধিক (
+(
)
) 0
।
- শূন্য বা আরও বেশি স্পেস (
*( )
), আবার।
*( )[qQ]?([uU][iI][tT])*( )
প্রস্থান কমান্ডের জন্য যা পরীক্ষা করে এটির একটি অনুক্রমের সাথে মেলে:
- শূন্য বা আরও বেশি স্থান (
*( )
)।
q
বা Q
( [qQ]
)।
- Ptionচ্ছিকভাবে - যেমন: শূন্য বা একটি সংঘটন (
?(
)
) - এর:
u
বা U
( [uU]
) এর পরে i
বা I
( [iI]
) এর পরে t
বা T
( [tT]
)
- শূন্য বা আরও বেশি স্পেস (
*( )
), আবার।
বৈকল্পিক: বর্ধিত নিয়মিত এক্সপ্রেশন সহ বৈধকরণ ইনপুট
আপনি যদি শেল গ্লোব না দিয়ে কোনও নিয়মিত অভিব্যক্তির বিরুদ্ধে ব্যবহারকারীর ইনপুট পরীক্ষা করতে পছন্দ করেন তবে আপনি এই সংস্করণটি ব্যবহার করতে পছন্দ করতে পারেন যা একই কাজ করে তবে ব্যবহার করে [[
এবং =~
( টেরডনের উত্তরের মতো ) পরিবর্তে case
এবং প্রসারিত গ্লোব্বিং।
#!/usr/bin/env bash
shopt -s nocasematch
declare -A cutoffs
cutoffs[F]=59 cutoffs[D]=69 cutoffs[C]=79 cutoffs[B]=89 cutoffs[A]=100
while read -erp 'Enter numeric grade (q to quit): '; do
# allow leading/trailing spaces, but not octal (e.g., "03")
if [[ ! $REPLY =~ ^\ *([1-9][0-9]*|0+)\ *$ ]]; then
[[ $REPLY =~ ^\ *q(uit)?\ *$ ]] && exit
echo "I don't understand that number."; continue
fi
for letter in F D C B A; do
((REPLY <= cutoffs[$letter])) && { echo $letter; continue 2; }
done
echo "Grade out of range."
done
এই পদ্ধতির সম্ভাব্য সুবিধাগুলি হ'ল:
এই বিশেষ ক্ষেত্রে, সিনট্যাক্সটি কিছুটা সহজ, কমপক্ষে দ্বিতীয় প্যাটার্নে যেখানে আমি ছাড়ার আদেশটি পরীক্ষা করি check এর কারণ হল আমি সেট করতে সক্ষম নয় ছিল nocasematch
শেল বিকল্প, এবং তারপর সব ক্ষেত্রে রুপভেদ q
এবং quit
স্বয়ংক্রিয়ভাবে আচ্ছাদনে ঢাকা।
shopt -s nocasematch
কমান্ড এটিই করে। shopt -s extglob
কমান্ড globbing এই সংস্করণে ব্যবহার করা হয় না যেমন বাদ দেওয়া হয়।
নিয়মিত অভিব্যক্তি দক্ষতা বাশের এক্সটগলবগুলিতে দক্ষতার চেয়ে বেশি সাধারণ।
ব্যাখ্যা: নিয়মিত প্রকাশ
=~
অপারেটরের ডানদিকে নির্দিষ্ট নিদর্শনগুলির জন্য , এখানে নিয়মিত প্রকাশগুলি কীভাবে কাজ করে তা এখানে।
^\ *([1-9][0-9]*|0+)\ *$
, যা সংখ্যার ইনপুট জন্য পরীক্ষা করে এটি একটি ক্রমের সাথে মেলে:
- সূচনা - অর্থাৎ, বাম প্রান্ত - রেখার (
^
)।
- শূন্য বা আরও বেশি (
*
প্রয়োগিত পোস্টফিক্স) স্পেস। কোনও স্থানকে সাধারণত \
নিয়মিত অভিব্যক্তিতে ছাড়ানো প্রয়োজন হয় না , তবে [[
সিনট্যাক্স ত্রুটি রোধ করার জন্য এটি প্রয়োজন ।
- একটি সাবস্ট্রিং (
(
)
) যা এর এক বা অন্য ( |
):
[1-9][0-9]*
: একটি ননজারো ডিজিট ( [1-9]
) এর পরে *
কোনও অঙ্কের শূন্য বা আরও বেশি ( , প্রয়োগ পোস্টফিক্স) [0-9]
)
0+
: এর এক বা একাধিক ( +
, প্রয়োগ পোস্টফিক্স) 0
।
- শূন্য বা আরও বেশি স্থান (
\ *
), আগের মতো।
- শেষ - অর্থাৎ ডান প্রান্ত - রেখার (
$
)।
case
লেবেলগুলির বিপরীতে যা পুরো এক্সপ্রেশনটির পরীক্ষা করা হচ্ছে তার বিপরীতে মেলে, =~
যদি তার বাম-হাতের এক্সপ্রেশনটির কোনও অংশ তার ডান হাতের এক্সপ্রেশন হিসাবে দেওয়া প্যাটার্নটির সাথে মিলে যায় তবে সত্য ফিরে আসে। এই অবস্থা হলো কেন ^
এবং $
নোঙ্গর, শুরুতে এবং লাইনের শেষে উল্লেখ, এখানে প্রয়োজন হয়, এবং পদ্ধতি প্রদর্শনে কিছু চিহ্নগুলি সিন্টেক্সের মিলা না case
এবং extglobs।
প্রথম বন্ধনী তৈরি করতে প্রয়োজন হয় ^
এবং $
এর অসম্বন্ধ প্রদানকারীর সাথে যুক্ত হন [1-9][0-9]*
এবং 0+
। অন্যথায় এটি সংশ্লেষ হবে ^[1-9][0-9]*
এবং 0+$
, এবং কোনও ননজারো ডিজিট দিয়ে শুরু হওয়া বা কোনও 0
(বা উভয়ই, যার মধ্যে এখনও অ-অঙ্কগুলি অন্তর্ভুক্ত থাকতে পারে) দিয়ে শেষ হওয়া কোনও ইনপুট মিলবে ।
^\ *q(uit)?\ *$
প্রস্থান কমান্ডের জন্য যা পরীক্ষা করে এটির একটি অনুক্রমের সাথে মেলে:
- লাইনের সূচনা (
^
)।
- শূন্য বা আরও বেশি স্থান (
\ *
, উপরের ব্যাখ্যাটি দেখুন)।
- চিঠি
q
। বা Q
, যেহেতু shopt nocasematch
সক্ষম রয়েছে।
- Ptionচ্ছিকভাবে - যেমন শূন্য বা একটি সংঘটন (পোস্টফিক্স
?
) - স্ট্রিংয়ের ( (
)
):
u
, তার পরে i
, অনুসরণ করে t
। বা, যেহেতু shopt nocasematch
সক্ষম করা u
হতে পারে U
; স্বাধীনভাবে, i
হতে পারে I
; এবং স্বাধীনভাবে, t
হতে পারে T
। (এটি হ'ল সম্ভাবনাগুলি সীমাবদ্ধ নয়uit
এবং UIT
))
- শূন্য বা আরও বেশি স্পেস আবার (
\ *
)।
- লাইনের শেষ (
$
)।