প্রিন্টফ কেন "সঙ্কুচিত" উমলৌত?


54

আমি যদি নিম্নলিখিত সাধারণ স্ক্রিপ্টটি কার্যকর করি:

#!/bin/bash
printf "%-20s %s\n" "Früchte und Gemüse"   "foo"
printf "%-20s %s\n" "Milchprodukte"        "bar"
printf "%-20s %s\n" "12345678901234567890" "baz"

এটি প্রিন্ট করে:

Früchte und Gemüse foo
Milchprodukte        bar
12345678901234567890 baz

অর্থাৎ, আমলাউটের সাথে পাঠ্য (যেমন ü) উমলৌটের প্রতি একটি চরিত্র দ্বারা "সঙ্কুচিত" হয়।

অবশ্যই, আমার কোথাও কিছু ভুল সেটিং আছে তবে আমি কোনটি হতে পারে তা নির্ধারণ করতে পারছি না।

যদি ফাইলটির এনকোডিংটি ইউটিএফ -8 হয় তবে এটি ঘটে।

যদি আমি এর এনকোডিংটি ল্যাটিন -১ এ পরিবর্তন করি তবে প্রান্তিককরণটি সঠিক, তবে আমলাতগুলি ভুলভাবে রেন্ডার হয়েছে:

Frchte und Gemse   foo
Milchprodukte        bar
12345678901234567890 baz

14
আপনি কি প্রিন্টফটি ইউটিএফ -8 এবং অন্যান্য মাল্টবাইটি চরসেট সম্পর্কে সচেতন হওয়ার প্রত্যাশা করছেন?
frostschutz

16
দেখে মনে হচ্ছে এটি অক্ষরের চেয়ে বাইট গণনা করছে; echo Früchte und Gemüse | wc -c -mপার্থক্য জন্য দেখুন ।
স্টিফেন কিট

7
@frostschutz Zsh এর printfহয়।
স্টিফেন কিট

10
হ্যাঁ, আমি আশা করি প্রিন্টফ ইউটিএফ -8 (কমপক্ষে) সম্পর্কে সচেতন থাকবেন।
রেনেনিফেনিগার

12
ভাল, এটা না। শক্ত ভাগ্য। ;-)
frostschutz

উত্তর:


87

POSIX প্রয়োজন printf এর %-20sপরিপ্রেক্ষিতে ওই 20 গণনা বাইট না অক্ষর যে যদিও সামান্য জ্ঞান করে তোলে যেমন printfপ্রিন্ট করতে হয় টেক্সট , ফরম্যাট (আলোচনা দেখুন অস্টিন গ্রুপ এ (POSIX) এবং bashমেইলিং তালিকা)।

printfএর builtin bashএবং অন্যান্য অধিকাংশ POSIX শাঁস যে সম্মান।

zshসেই নির্বোধ প্রয়োজনকে উপেক্ষা করে (এমনকি shঅনুকরণেও) তাই printfআপনি সেখানে যেমন প্রত্যাশা করতেন তেমন কাজ করে। জন্য একই printfএর builtin fish(একটি POSIX মত শেল)।

üঅক্ষর (U + এ 00FC), যখন হল UTF-8 এনকোড দুই বাইট (0xc3 এবং 0xbc), যা অমিল ব্যাখ্যা তৈরি করা হয়।

$ printf %s 'Früchte und Gemüse' | wc -mcL
    18      20      18

এই স্ট্রিংটি 18 টি অক্ষর দ্বারা তৈরি, 18 কলাম প্রশস্ত ( ইনপুটটিতে প্রশস্ত রেখার প্রস্থের প্রস্থের প্রতিবেদন করার জন্য -Lএকটি জিএনইউ wcএক্সটেনশন হওয়া ) তবে 20 বাইটে এনকোড করা রয়েছে।

ইন zshবা fishটেক্সট সঠিকভাবে প্রান্তিককৃত হবে।

এখন, এমন কিছু অক্ষরও রয়েছে যেগুলির 0-প্রস্থ রয়েছে (যেমন ইউ + 0308, সংমিশ্রণ ডায়ারিসিসের মতো অক্ষরগুলি সমন্বিত) বা অনেক এশিয়াটিক স্ক্রিপ্টগুলির মতো ডাবল-প্রস্থ রয়েছে (ট্যাবের মতো নিয়ন্ত্রণ অক্ষরের উল্লেখ না করা) এবং এমনকি zshবিন্যস্ত হয় না যারা সঠিকভাবে।

উদাহরণ zsh:

$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
  u|
  ü|
 ü|
  ᄀ|

ইন bash:

$ printf '%3s|\n' u ü $'u\u308' $'\u1100'
  u|
 ü|
ü|
ᄀ|

ksh93প্রদর্শনের প্রস্থের %Lsক্ষেত্রে প্রস্থটি গণনা করার জন্য একটি ফর্ম্যাট স্পেসিফিকেশন রয়েছে ।

$ printf '%3Ls|\n' u ü $'u\u308' $'\u1100'
  u|
  ü|
  ü|
 ᄀ|

এটি এখনও কার্যকর হয় না যদি পাঠ্যটিতে TAB এর মতো নিয়ন্ত্রণের অক্ষর থাকে (কীভাবে এটি হতে পারে তা printfজানতে হবে যে আউটপুট ডিভাইসে ট্যাব স্টপগুলি কতটা দূরে রয়েছে এবং এটি কোন অবস্থানে মুদ্রণ শুরু করে)। এটি ব্যাকস্পেস অক্ষরগুলির সাথে দুর্ঘটনার দ্বারা কাজ করে (যেমন roffআউটপুটে যেখানে X(গা bold় X) লেখা থাকে X\bX) যদিও ksh93সমস্ত নিয়ন্ত্রণ অক্ষরকে প্রস্থ বলে বিবেচনা করে -1

অন্যান্য বিকল্প হিসাবে, আপনি চেষ্টা করতে পারেন:

printf '%s\t|\n' u ü $'u\u308' $'\u1100' | expand -t3

এটি কিছু expandবাস্তবায়ন নিয়ে কাজ করে (জিএনইউ এর যদিও নয়)।

জিএনইউ সিস্টেমে আপনি জিএনইউ ব্যবহার করতে পারেন awkযার printfসংখ্যাগুলি চরগুলিতে গণনা করা হয় (বাইটস নয়, প্রদর্শন প্রশস্ততা নয়, তবে 0-প্রশস্ত বা 2-প্রস্থের অক্ষরের জন্য ঠিক নেই তবে আপনার নমুনার জন্য ঠিক আছে):

gawk 'BEGIN {for (i = 1; i < ARGC; i++) printf "%-3s|\n", ARGV[i]}
     ' u ü $'u\u308' $'\u1100'

যদি আউটপুটটি কোনও টার্মিনালে যায়, আপনি কার্সার পজিশনিং এস্কেপ সিকোয়েন্সগুলিও ব্যবহার করতে পারেন। ভালো লেগেছে:

forward21=$(tput cuf 21)
printf '%s\r%s%s\n' \
  "Früchte und Gemüse"    "$forward21" "foo" \
  "Milchprodukte"         "$forward21" "bar" \
  "12345678901234567890"  "$forward21" "baz"

2
এটা ভুল। üCaracter যেমন গঠিত হতে পারে u+ + ¨, যা 3 বাইট। প্রশ্নের ক্ষেত্রে, এটি 2 টি অক্ষর হিসাবে এনকোড করা থাকলেও সমস্তগুলি üসমানভাবে তৈরি হয় না।
ইসমাইল মিগুয়েল

6
@ ইসমাইল মিগুয়েল, u\u308একটি গ্লাইফ / গ্রাফেম / গ্রাফেম-ক্লাস্টারের জন্য দুটি অক্ষর ( wc -mকমপক্ষে ইউনিক্স / অর্থে) এবং এটি ইতিমধ্যে উল্লিখিত এবং এই উত্তরে অন্তর্ভুক্ত রয়েছে।
স্টাফেন চেজেলাস

"যেটি প্রিন্টফ পাঠ্য মুদ্রণ করাকে সামান্য বোঝায়" ওয়েল, কেউ যুক্তি দিতে পারেন যে প্রিন্টফ সি চরগুলি (বাইট) নিয়ে কাজ করে; এটি টেক্সট লোকেলগুলির সাথে ডিল করা উচিত নয় এবং এতে (সম্ভবত মাল্টিবাইট) চরসেট এনকোডিং বোঝার বোঝা থাকা উচিত নয়। কিন্তু প্রতিরক্ষা এই লাইনটি (আইএসও সি 99) সাথে বিবাদ করে যে "% s" বাইট কাটা "অবৈধ" পাঠ্য (সংক্ষিপ্ত অক্ষর) এর ফলস্বরূপ হওয়া উচিত নয়। গ্লিবসি এমনকি সে ক্ষেত্রে ব্যর্থ হয় (এটি কিছুই প্রিন্ট করে)। একটি বাস্তব জগাখিচুড়ি। postgresql.org/message-id/…
লিওনব্লয় 21 '12

@ লেওনব্লয়, এটি সি এর অনুভূতি বোধ করতে পারে printf(3)(আপনি যে সি 99 এর প্রয়োজনীয়তার পরে সামান্য জ্ঞান বোধ করছেন, তার জন্য ধন্যবাদ), তবে printf(1)প্রতিটি শেল অপারেটর বা অক্ষরের সাথে অন্যান্য পাঠ্য ইউটিলিটি চুক্তি হিসাবে ইউটিলিটি নয় (বা অক্ষরগুলির সাথেও ডিল করার জন্য সংশোধন করা হয়েছিল) যেমনটি wcপেয়েছিল -m( বাইট-c থাকাকালীন ) বা তার পরে পেয়েছিল বাইটস বাদে অন্য কিছু বোঝাতে পারে। cut-b-c
স্টাফেন চেজেলাস

এমনকি এটি বাইটের পরিবর্তে অক্ষর ব্যবহার করলেও এটি কলামগুলি সারিবদ্ধ করার জন্য উপযুক্ত হবে না। আপনার প্রতিটি অক্ষর কত টার্মিনাল সেল দখল করে তা জানতে হবে যা অক্ষর অনুসারে পরিবর্তিত হয় (0-2)।
আর ..

10

যদি আমি এর এনকোডিংটি ল্যাটিন -১ এ পরিবর্তন করি তবে প্রান্তিককরণটি সঠিক, তবে আমলাতগুলি ভুলভাবে রেন্ডার হয়েছে:

Frchte und Gemse   foo
Milchprodukte        bar
12345678901234567890 baz

প্রকৃতপক্ষে, না, তবে আপনার টার্মিনালটি লাতিন -১ কথা বলে না, এবং তাই আপনি উমলাতদের চেয়ে জাঙ্ক পান।

আপনি আইকনভি ব্যবহার করে এটি ঠিক করতে পারেন:

printf foo bar | iconv -f ISO8859-1 -t UTF-8

(অথবা আইকনভিতে পাইপযুক্ত পুরো শেল স্ক্রিপ্টটি চালান)


3
এটি একটি দরকারী মন্তব্য কিন্তু মূল প্রশ্নের উত্তর দেয় না।
জারিত 14

1
@ জিরিট কিভাবে? ল্যাটিন 1-এ মুদ্রণের সময় যদি প্রিন্টফ সঠিক কাজ করে তবে ল্যাটিন 1 এ এটি মুদ্রণ করে পরে এটি ইউটিএফ -8 এ রূপান্তর করতে হবে? আমার কাছে মূল প্রশ্নের সঠিক সমাধানের মতো বলে মনে হচ্ছে।
ওয়াউটার ভারহেলস্ট

1
মূল প্রশ্নটি হ'ল "কেন এটি উমলৌত সঙ্কুচিত হচ্ছে", উত্তরটি (অন্যান্য উত্তরের মতো) "কারণ এটি utf-8 সমর্থন করে না"। এটি জিজ্ঞাসা করছে না যে উমলাটগুলি কেন ভুল উপস্থাপিত হয় বা আমি কীভাবে উমলাউট রেন্ডারিং ঠিক করতে পারি । যে কোনও উপায়ে, আপনার পরামর্শটি utf-8 এর উপসেটের জন্য কার্যকর যেটি iso8859-1 (কেবল) হিসাবে উপস্থাপিত হতে পারে।
15-18 এ জারিত

4
@ ওউটারভারহেলস্ট, হ্যাঁ এটি কেবলমাত্র পাঠ্যকেই প্রয়োগ করতে পারে যা একক বাইট চরসেটে এনকোড করা যেতে পারে।
স্টাফেন চেজেলাস

3
আমিও "আমি ত্রুটিযুক্ত আউটপুটটিকে আপত্তি করি না, যতক্ষণ জানি আমি কেন জানি" এর চেয়ে "আমি কীভাবে আউটপুটটি সঠিকভাবে পেতে পারি" হিসাবে প্রশ্নটি পড়েছি।
মিস্টার লিস্টার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.