كيفية إيقاف ANSI اللون رموز لخبطة printf المحاذاة ؟
-
03-10-2019 - |
سؤال
لقد اكتشفت هذا في حين باستخدام روبي printf ، ولكنه ينطبق أيضا على ج printf.
إذا قمت بتضمين ANSI اللون هروب رموز في سلسلة الإنتاج ، فإنه عبث المحاذاة.
روبي:
ruby-1.9.2-head > printf "%20s\n%20s\n", "\033[32mGreen\033[0m", "Green"
Green # 6 spaces to the left of this one
Green # correctly padded to 20 chars
=> nil
نفس الخط في برنامج C تنتج نفس الناتج.
هناك على أية حال الحصول على printf (أو شيء آخر) مواءمة المخرجات وليس إضافة مساحات غير المطبوعة الشخصيات ؟
هل هذا خطأ أم أن هناك سبب وجيه لذلك ؟
تحديث: منذ printf لا يمكن الاعتماد على محاذاة البيانات عندما يكون هناك رموز ANSI واسعة حرف ، هل هناك أفضل الممارسات طريقة اصطفاف الملونة جداول البيانات في وحدة التحكم في روبي ؟
المحلول
أنا لا أتفق مع توصيف '9 المساحات بعد الأخضر الأخضر'.يمكنني استخدام بيرل بدلا من روبي, ولكن إذا كنت تستخدم تعديل البيان ، الطباعة رمزا الأنابيب بعد سلسلة أحصل على:
perl -e 'printf "%20s|\n%20s|\n", "\033[32mGreen\033[0m", "Green";'
Green|
Green|
هذا يظهر لي أن printf()
بيان عد 14 الشخصيات في السلسلة ، لذلك إرفاق مسبقا 6 مساحات لإنتاج 20 حرفا محاذاة إلى اليمين.ومع ذلك ، فإن محطة ابتلع 9 من تلك الشخصيات تفسيرها كما يتغير اللون.حتى الإخراج ظهر 9 شخصيات أقصر مما كنت أرغب في ذلك.ومع ذلك ، printf()
لم تتم طباعة 9 الفراغات بعد أول 'الأخضر'.
بشأن أفضل الممارسات الانحياز الناتج (مع colourization), أعتقد أنك سوف تحتاج إلى أن يكون كل الحجم و الانحياز حقل محاط بسيطة '%s' الحقول التي تتعامل مع colourization:
printf "%s%20.20s%s|%s%-10d%s|%s%12.12s%s|\n",
co_green, column_1_data, co_plain,
co_blue, column_2_data, co_plain,
co_red, column_3_data, co_plain;
حيث من الواضح ، co_XXXX
المتغيرات (الثوابت?) تحتوي على تسلسلات الهروب إلى التبديل إلى اسمه اللون (و co_plain
قد يكون أفضل co_black
).إذا اتضح أنك لا تحتاج colourization على بعض الحقول ، يمكنك استخدام سلسلة فارغة في مكان co_XXXX
المتغيرات (أو يطلق عليه co_empty
).
نصائح أخرى
إنها ليست خطأ: لا توجد طريقة يجب أن يعرفها روبي (على الأقل داخل printf ، ستكون قصة مختلفة عن شيء مثل اللعنات) أن stdout ستذهب إلى محطة تتفهم تسلسل الهروب VT100.
إذا كنت لا تقوم بضبط ألوان الخلفية ، فقد يكون شيء من هذا القبيل فكرة أفضل:
GREEN = "\033[32m"
NORMAL = "\033[0m"
printf "%s%20s%s\n", GREEN, "Green", NORMAL
printf
لا تعد محددات عرض الحقل مفيدة لمحاذاة البيانات الجدولية وعناصر الواجهة ، وما إلى ذلك. بصرف النظر عن مسألة أحرف التحكم التي اكتشفتها بالفعل ، هناك أيضًا أحرف غير متوقعة وعرض مزدوج سيتعين على برنامجك التعامل معها إذا كنت لا ترتدي " تريد الحد من الأشياء على تشفير الأحرف القديمة (التي يعتبرها العديد من المستخدمين إهمالًا).
إذا أصرت على استخدام printf
بهذه الطريقة ، ربما تحتاج إلى القيام بشيء مثل:
printf("%*s\n%*s\n", bytestopad("\033[32mGreen\033[0m", 20), "\033[32mGreen\033[0m", bytestopad("Green", 20), "Green");
أين bytestopad(s,n)
هي وظيفة تكتبها تحسب عدد البايتات الإجمالية اللازمة (مساحات الحشو سلسلة) لتؤدي إلى السلسلة s
احترف n
الأعمدة الطرفية. هذا من شأنه أن يتضمن تحليل الهروب ومعالجة الأحرف متعددة الفئران واستخدام منشأة (مثل Posix wcwidth
وظيفة) للبحث عن عدد الأعمدة الطرفية التي يأخذها كل منها. لاحظ استخدام *
بدلاً من عرض مجال ثابت في printf
سلسلة تنسيق. هذا يسمح لك بتمرير int
حجة ل printf
لعرض الحقل المتغير وقت التشغيل.
أود أن أفصل أي تسلسل هروب من النص الفعلي لتجنب المسألة برمتها.
# in Ruby
printf "%s%20s\n%s%20s\n", "\033[32m", "Green", "\033[0m", "Green"
أو
/* In C */
printf("%s%20s\n%s%20s\n", "\033[32m", "Green", "\033[0m", "Green");
نظرًا لأن تسلسل ANSI Escape ليس جزءًا من Ruby أو C لا يعتقد أنه يحتاج إلى معاملة هذه الشخصيات خاصة ، وهي محقة في ذلك.
إذا كنت ستقوم بالكثير من الأشياء الملونة الطرفية ، فيجب عليك النظر في اللعنات والرسومات التي توفر وظائف لإجراء تغييرات في الألوان التي تعمل مع العديد من أنواع المحطات المختلفة. كما أنها توفر المزيد من الوظائف ، مثل النوافذ المستندة إلى النص ، ومفاتيح الوظائف ، وأحيانًا تفاعل الماوس.
إليك الحل الذي توصلت إليه مؤخرًا. هذا يتيح لك الاستخدام color("my string", :red)
في printf
بيان. أحب استخدام نفس سلسلة التنسيق للرؤوس والبيانات - الجافة. هذا يجعل ذلك ممكنا. أيضا ، أنا استخدم قوس المطر جوهرة لتوليد رموز الألوان. إنه ليس مثاليًا ولكنه ينجز المهمة. ال CPAD
يحتوي التجزئة على قيمتين لكل لون ، المقابل للحشو الأيسر واليمين ، على التوالي. وبطبيعة الحال ، يجب أن يمتد هذا الحل لتسهيل الألوان والمعدلات الأخرى مثل الجريئة والتسديد.
CPAD = {
:default => [0, 2],
:green => [0, 3],
:yellow => [0, 2],
:red => [0, 1],
}
def color(text, color)
"%*s%s%*s" % [CPAD[color][0], '', text.color(color), CPAD[color][1], '']
end
مثال:
puts "%-10s %-10s %-10s %-10s" % [
color('apple', :red),
color('pear', :green),
color('banana', :yellow)
color('kiwi', :default)
]