المسارات
/
Python
Python
/
المنهج
/
تنسيق السلاسل النصية
تن

تنسيق السلاسل النصية في Python

1 تمرين

نبذة عن تنسيق السلاسل النصية

تنسيق السلاسل النصية في Python

تنسيق السلاسل النصية هو عملية تحويل القيم إلى سلاسل نصية وإدراجها في قالب سلسلة نصية. يؤكد Zen of Python أنه ينبغي أن تكون هناك «طريقة واضحة واحدة لفعل شيء ما في Python». لكن حين يتعلق الأمر بتنسيق السلاسل النصية، تصبح الأمور... أقل زهدًا.

قد يفاجئك أن تعرف أن هناك أربع طرق رئيسية لتنسيق السلاسل النصية في Python، كل واحدة منها تناسب سيناريو مختلفًا. يعود بعض ذلك إلى تاريخ Python الطويل، وبعضه إلى اعتبارات مثل التدويل أو تنقية المدخلات. سنبدأ بأحدث الإضافات إلى صندوق أدوات تنسيق السلاسل النصية، ثم نعود بالترتيب إلى التنسيق «بالنمط القديم» أو «نمط printf()».

الاستيفاء الحرفي للسلاسل النصية: f-string

أُدخلت f-string في Python 3.6، وf-string (اختصارًا لعبارة «السلاسل النصية المنسقة») أو الاستيفاء الحرفي للسلاسل النصية، هي وسيلة لتقييم التعبيرات والسلاسل النصية (وتنسيقها) بسرعة وكفاءة إلى نوع str باستخدام البادئة f (أو F) قبل علامات الاقتباس (بهذا الشكل: f'{object}').

يمكن استخدام f-string مع جميع أنواع الاقتباس المحيطة، مثل أحادية السطر (' أو ") ومتعددة الأسطر (''' أو """). أي متغيرات أو تعبيرات أو أنواع أخرى تُوضع داخل الأقواس المعقوفة {} تُقيَّم أولًا، ثم تُحوَّل إلى str، ثم تُدمج أخيرًا مع أي str خارج الأقواس المعقوفة.

في هذا المثال، نُدرج قيمتي متغيرين في جملة (واحدة str وأخرى float):

>>> name = 'eighth'
>>> value = 1/8

# The f-string, using the two values.
# The .2f format code truncates, so the value displays as 0.12.
>>> f'An {name} is approximately {value:.2f}.'
'An eighth is approximately 0.12.'

يمكن أن تكون التعبيرات المُقيَّمة أي شيء تقريبًا. ومن بين النطاق الواسع من الاحتمالات التي يمكن تقييمها: str، والأعداد، والمتغيرات، والتعبيرات الحسابية، والتعبيرات الشرطية، والأنواع المدمجة، والشرائح، والدوال، وتعبيرات lambda، والاستيعابات، أو أي كائنات معرَّف لها __str__ أو __repr__.

ننتقل من البسيط إلى المعقد:

إدراج متغير — أبسط استخدام لـ f-string هو وضع متغير مباشرة داخل السلسلة النصية.

# Assigning a variable.
>>> name = "World"

# Inserting that variable.
>>> f'Hello, {name}!'
'Hello, World!'

التعبيرات داخل {} — يمكن تقييم أي تعبير Python صالح داخل الأقواس. لاحظ أن استخدام علامات الاقتباس المزدوجة داخل f-string بين علامتي اقتباس مفردتين (أو العكس) يغني عن تسلسلات الهروب:

# A dictionary of key:value pairs.
>>> waves = {'water': 1, 'light': 3, 'sound': 5}

# Inserting the whole dict.
>>> f'Wave ranks: {waves}'
"Wave ranks: {'water': 1, 'light': 3, 'sound': 5}"

# An expression can be evaluated inline:
>>> f"Tenfold the value of 'light' is {waves['light'] * 10}."
"Tenfold the value of 'light' is 30."

# A method call can also be evaluated inline:
>>> f'{"hello world!".title()} is a classic greeting.'
'Hello World! is a classic greeting.'

# An f-string can be nested inside another f-string:
>>> f"{f'hello world!'.title()} is a classic greeting."
'Hello World! is a classic greeting.'

تنسيق المخرجات — يمكن استخدام لغة المواصفات المصغّرة للتنسيق للتحكم في المحاذاة ودقة الأعداد والمزيد. تأتي مواصفة التنسيق بعد القيمة، مفصولة بعلامة :.

# Right-align a value to ten characters, and round it to 3 decimal places.
>>> value = 1 / 7
>>> f'One seventh is {value:10.3f}.'
'One seventh is      0.143.'

# A format specification can be set using variables as well.
>>> padding = 10
>>> precision = 3
>>> f'One seventh is {value:{padding}.{precision}f}.'
'One seventh is      0.143.'

جمع كل ذلك معًا — المتغيرات، والتعبيرات، واستدعاءات الدوال، وتنسيق المخرجات:

>>> precision = 3
>>> f"{30e8 * 111_000:6.{precision}e}"
'3.330e+14'

>>> verb = 'meet'
>>> the_end = ['end', 'of', 'transmission']
>>> f'"Have a {"NICE".lower()} day, I will {verb} you after {30e8 * 111_000:6.{precision}e} light-years."{the_end}'
'"Have a nice day, I will meet you after 3.330e+14 light-years."[\'end\', \'of\', \'transmission\']'

# Did you notice the escaped single-quotes in the previous example?
# Using double quotes instead of single quotes for the f-string means the list's single-quoted strings print cleanly.
>>> f"Have a nice day. {the_end}"
"Have a nice day. ['end', 'of', 'transmission']"

هناك قيدان رئيسيان يجب الانتباه إليهما. لا يمكن أن تكون تعبيرات f-string فارغة. إضافة إلى ذلك، قبل Python 3.12، لم يكن مسموحًا لها أن تحتوي على تعليقات.

>>> f"An empty expression will error: {}"
SyntaxError: f-string: empty expression not allowed

>>> word = 'word'
>>> f"""A comment in a triple quoted f-string: {
    word # I chose a nice variable
}"""
'A comment in a triple quoted f-string: word'
Caution

لا يمكن استخدام استيفاء السلاسل النصية مع واجهة GNU gettext للتدويل (I18N) والتوطين (L10N)، لذا يُوصى باستخدام الصنف string.Template أو الطريقة str.format() الموضحة أدناه بدلًا من f-string في أي سيناريوهات ترجمة «تغليف السلاسل».

ضع في اعتبارك أيضًا أن استخدام التعبيرات داخل أقواس f-string المعقوفة {} يشبه استخدام eval() أو exec()، لذا فهو ليس آمنًا تمامًا ويجب ألا يُستخدم أبدًا مع مدخلات المستخدم.

الطريقة str.format()

تستبدل الطريقة str.format() العناصر النائبة داخل السلسلة النصية بقيم تُمرَّر كوسائط إلى الدالة. وتُحدَّد العناصر النائبة بالأسماء ({price}) أو الأعداد ({0} أو الفهارس) أو حتى عناصر نائبة فارغة (موضعية) {}.

على سبيل المثال:

# A named placeholder and a positional placeholder.
>>> 'My text: {placeholder_1} and {}.'.format(12, placeholder_1='named placeholder')
'My text: named placeholder and 12.'

كما هو الحال مع f-string، تدعم str.format() في Python مجموعة كاملة من مواصفات التنسيق في اللغة المصغّرة التي يمكن استخدامها لمحاذاة النص واقتطاع الأعداد العشرية والمزيد.

نمط مواصفة التنسيق الكامل هو {[<name>][!<conversion>][:<format_specifier>]}:

  • يمكن أن يكون <name> عنصرًا نائبًا مسمّى، أو عددًا، أو فارغًا.
  • !<conversion> اختياري، ويجب أن يكون واحدًا من هذه التحويلات الثلاثة: !s من أجل str()، أو !r من أجل repr()، أو !a من أجل ascii(). وبشكل افتراضي، يُستخدم str().
  • :<format_specifier> اختياري، ويتحكم في كيفية عرض القيمة. ويمكن العثور على مزيد من المعلومات حول الخيارات الممكنة هنا.

مثال على التحويلات لحرف ذي علامة تشكيل:

# Fills in the object at index zero, converted to a string.
>>> 'An e with an umlaut: {0!s}'.format('ë')
'An e with an umlaut: ë'


# Fills in the object at index zero, converted to a repr.
>>> 'An e with an umlaut (object representation): {0!r}'.format('ë')
"An e with an umlaut (object representation): 'ë'"


# Fills in the object at index zero, converted to ASCII.
>>> 'An e with an umlaut converted into ASCII: {0!a}'.format('ë')
"An e with an umlaut converted into ASCII: '\xeb'"


# Fills in the object in the first position,
# then fills in the object in the second position formatted as a repr.
>>> 'She said her name is not {} but {!r}.'.format('Chloe', 'Zoë')
"She said her name is not Chloe but 'Zoë'."

أمثلة على مواصفات التنسيق الشائعة:

# Integer and binary/hex representations of the same number.
>>> my_num = 42
>>> f"{my_num} in binary is {my_num:b}. In hex, it is {my_num:x}"
"42 in binary is 101010. In hex, it is 2a"

# Alignment: left (<), right (>), and center (^) using up to ten characters total.
>>> f"[{"left":<10}] [{"right":>10}] [{"center":^10}]"
"[left      ] [     right] [  center  ]"

# Float precision and scientific notation (up to three decimal places).
>>> pi = 3.141592653589793
>>> f"Fixed: {pi:.3}  Scientific: {pi:.3e}"
"Fixed: 3.142  Scientific: 3.142e+00"

# Thousands separator and percentage.
>>> balance = 1000
>>> rate = 0.0225
>>> f"Balance: ${balance:,.0f}  Interest rate: {rate:.1%}"
"Balance: $1,000  Interest rate: 2.2%"

# Putting it all together:
>>> items = [("Widget", 1250, 9.991), ("Gadget", 37, 24.503), ("Doohickey", 4, 149.002)]
>>> header = f"{"Item":<12} {"Qty":>6} {"Price":>9}"
>>> print(header)
Item            Qty     Price
>>> for name, qty, price in items:
...     print(f"{name:<12} {qty:>6} {price:>9.2f}")
Widget         1250      9.99
Gadget           37     24.50
Doohickey         4    149.00

توجد أمثلة إضافية في نهاية هذا التوثيق.

التنسيق بـ %، أو التنسيق بنمط printf()

استخدام العامل % للتنسيق هو أقدم طريقة لتنسيق السلاسل النصية في Python. وهو مستمد من لغة C، ويتيح استخدام وسائط موضعية لبناء str.

وقد حلّت محل هذه الطريقة كلٌّ من f-string وstr.format()، ولهذا يُطلق على التنسيق بـ % لقب «النمط القديم». ولا يزال من الممكن العثور عليها في Python 2 و/أو الكود القديم. ومع أن استخدام هذه الطريقة سيعمل في Python 3.x، فعادةً ما يُتجنَّب التنسيق بـ % لأنه عرضة للأخطاء، وأقل كفاءة، وخياراته المتاحة أقل، وأي عدم تطابق بين العنصر النائب والوسيطة يمكن أن يُطلق استثناءً. استخدام العامل % يشبه printf()، لذا يُسمى أحيانًا أيضًا تنسيق printf.

# Assigning a variable.
>>> name = "Anna-conda"

# Building a string using %.
>>> "The snake's name is %s." % name
"The snake's name is Anna-conda."

في المثال أعلاه، يستبدل العامل % العنصر النائب %s بالمتغير name أثناء التشغيل. وإذا أردت إضافة عدة متغيرات إلى سلسلة نصية، فعليك تمرير tuple يحتوي على كائن واحد لكل عنصر نائب بعد العامل %:

# Assigning variables.
>>> name = "Billy the Kid"
>>> fruit = "grapes"

# Building a string using %.
>>> "Surprisingly, %s's favorite snack was %s." %(name, fruit)
"Surprisingly, Billy the Kid's favorite snack was grapes."

سلاسل القوالب النصية

‏string.Template() (يجب عدم الخلط بينه وبين t-strings في Python 3.14) هو صنف من وحدة string (على عكس النوع str المدمج)، وهو جزء من المكتبة القياسية في Python، لكن يجب استيراده لاستخدامه. تدعم سلاسل القوالب الاستبدال القائم على $، وهي أبسط بكثير وأقل قدرة من الخيارات الأخرى المذكورة هنا. ومع ذلك، يمكن أن تكون مفيدة جدًا في التدويل المعقد أو تنقية المدخلات الخارجية.

يُعدّ string.Template أكثر أمانًا لمدخلات المستخدم غير الموثوقة لأنه يمنع تقييم تعبيرات عشوائية أو الوصول إلى خصائص الكائنات، مما يحدّ من هجمات حقن سلاسل التنسيق.

>>> from string import Template

>>> name = "Anna-Conda"

# Creating a Template with placeholder text.
>>> template_string = Template("The snake called `$snake_name` has escaped!")

# Calling .substitute() to replace the placeholder with a value.
>>> template_string.substitute(snake_name=name)
'The snake called `Anna-Conda` has escaped!'

يمكن العثور على مزيد من المعلومات حول string.Template في التوثيق الخاص بـ Python.

كيف تختار طريقة التنسيق التي تستخدمها؟

مع كل هذه الخيارات واللغات المصغّرة، كيف تقرر ما الذي تستخدمه عند تنسيق السلاسل النصية في Python؟ إليك بعض الإرشادات السريعة:

  1. ‏f-string هي الأحدث والأسهل قراءة. إذا لم تكن بحاجة إلى التدويل، فينبغي أن تكون الطريقة المفضلة لـ Python 3.6 فما فوق.

  2. ‏str.format() متعددة الاستخدامات وقوية ومتوافقة مع كلٍّ من gnu gettext ومعظم إصدارات Python.

  3. إذا كنت بحاجة إلى البساطة والأمان و/أو التدويل الكثيف، فيمكن استخدام string.Template() للحدّ من المخاطر عند التعامل مع مدخلات المستخدمين، ولتغليف سلاسل الترجمة.

  4. يُعدّ العامل % عمومًا مهمَلًا بالنسبة إلى الكود الجديد، رغم أنه لا يزال يعمل في Python الحديثة. وينبغي أن يُستخدم في الغالب للتوافق مع قواعد أكواد أقدم. فالتنسيق بـ % أكثر عرضة للأخطاء (وأقل وظائف) من الطرق الأخرى، ويمكن أن يؤدي إلى مشكلات في عرض الأحرف غير التابعة لـ ASCII. تحقق من توزيعة Python الخاصة بك لمعرفة تفاصيل الدعم إذا كنت تنوي استخدامه.

إذا أردت التعمق أكثر، فإن كل ما يتعلق بالتنسيق وأفضل ممارسات تنسيق السلاسل النصية في Python نقطتا بداية جيدتان.

تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة