Pandas: عمليات النص

آخر تحديث: 2026-08-26

النص في البيانات الواقعية لا يكون نظيفًا أبدًا — مسافات بيضاء إضافية، تنسيق غير متسق، أحرف خاصة، صيغ مختلطة. جلب وصول Pandas .str التحويل المتسلسل إلى عمليات السلاسل النصية: تنظيف عمود كامل من النص بسطر واحد من الكود، أسرع حتى 100 مرة من حلقة بايثون. يغطي هذا القسم أكثر طرق السلاسل النصية استخدامًا ويوضح لك كيفية بناء خطوط أنابيب تنظيف متسلسلة.

⚠️ ملاحظة: يتطلب الكود أدناه بيئة بايثون محلية للتشغيل.

1. What You Will Learn


2. تنظيف مدخلات المستخدم من كارول

(1) المشكلة: مدخلات المستخدم تأتي بأشكال متنوعة

بيانات المستخدم التي جمعتها كارول فوضوية:

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['  alice  ', 'BOB', 'Charlie!', '  carol  ', 'DaVid123'],
    'email': ['alice@EXAMPLE.com', 'bob@company.ORG', 'charlie@uni.edu',
              'CAROL@example.COM', 'david@test.net'],
    'phone': ['555-0100', '(555) 0200', '555.0300', '+1-555-0400', '5550500']
})
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) وتابع. قد تتغير القيم الفعلية قليلاً اعتمادًا على إصدار pandas الخاص بك.

(2) الحل: سلسلة التنظيف باستخدام .str

▶ مثال: تنظيف النص بسلسلة أوامر (الصعوبة ⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['  alice  ', 'BOB', 'Charlie!', '  carol  ', 'DaVid123'],
    'email': ['alice@EXAMPLE.com', 'bob@company.ORG', 'charlie@uni.edu',
              'CAROL@example.COM', 'david@test.net']
})

# سلسلة أوامر .str: strip → replace → title
df['name_clean'] = (df['name']
    .str.strip()
    .str.replace(r'[^a-zA-Z ]', '', regex=True)
    .str.title()
)
print(df[['name', 'name_clean']])
#          name name_clean
# 0    alice        Alice
# 1         BOB        Bob
# 2   Charlie!    Charlie
# 3     carol        Carol
# 4   DaVid123       David

# تحويل نطاق البريد الإلكتروني إلى أحرف صغيرة
df['email_clean'] = df['email'].str.lower()
print(df['email_clean'])
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) وتابع. قد تتغير القيم الفعلية قليلاً اعتمادًا على إصدار pandas الخاص بك.

3. Accessor .str

(1) .str مقابل كائن str في بايثون

الميزة كائن str في بايثون Pandas .str
يعمل على نص واحد عمود كامل (متجه)
التعامل مع القيم المفقودة (NaN) يثير خطأ يتخطاها تلقائيًا (يعيد NaN)
الاتصال المتسلسل (Chaining) غير مدعوم ✅ استدعاءات متتالية
الأداء حلقة بطيئة → متجه → سريع

▶ مثال

TEXT 📖 للعرض فقط
> **الناتج:** قم بتشغيل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقًا — قم بتثبيتها محليًا (`pip install pandas`) واتبع الأمثلة. القيم الفعلية قد تختلف قليلاً حسب إصدار مكتبتك pandas.

: طرق .str الأساسية (الصعوبة ⭐)

PYTHON
import pandas as pd

s = pd.Series(['Hello World', 'pandas', 'DATA SCIENCE', None, 'python'])

# تحويل حالة الأحرف
print(s.str.lower())    # hello world, pandas, data science, NaN, python
print(s.str.upper())    # HELLO WORLD, PANDAS, DATA SCIENCE, NaN, PYTHON
print(s.str.title())    # Hello World, Pandas, Data Science, NaN, Python
print(s.str.capitalize())  # Hello world, Pandas, Data science, NaN, Python

# المسافات البيضاء
s2 = pd.Series(['  hello  ', '\tworld\n', '  pandas  '])
print(s2.str.strip())    # hello, world, pandas
print(s2.str.lstrip())   # hello  , world\n, pandas  
print(s2.str.rstrip())   #   hello, \tworld,   pandas

# الطول
print(s.str.len())       # 11, 6, 12, NaN, 6
TEXT 📖 للعرض فقط
> **الناتج:** قم بتشغيل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقًا — قم بتثبيتها محليًا (`pip install pandas`) واتبع الأمثلة. القيم الفعلية قد تختلف قليلاً حسب إصدار مكتبتك pandas.

4. replace / contains / match

(1) replace

▶ مثال

TEXT 📖 للعرض فقط
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on your pandas version.

: استبدال النصوص باستخدام replace (الصعوبة ⭐⭐)

PYTHON
import pandas as pd

s = pd.Series(['price: $100', 'price: $200', 'cost: €50'])

# Simple replacement
print(s.str.replace('$', 'USD'))
# price: USD100, price: USD200, cost: €50

# Regex replacement
print(s.str.replace(r'[\$€]', '', regex=True))
# price: 100, price: 200, cost: 50

# Replace multiple patterns
phones = pd.Series(['555-0100', '(555) 0200', '555.0300'])
clean = phones.str.replace(r'[^0-9]', '', regex=True)
print(clean)  # 5550100, 5550200, 5550300
TEXT 📖 للعرض فقط
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on your pandas version.

(2) contains / startswith / endswith

▶ مثال

TEXT 📖 للعرض فقط
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on your pandas version.

: تصفية النصوص بناءً على شرط (الصعوبة ⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['Alice Johnson', 'Bob Smith', 'Charlie Brown', 'Carol White'],
    'email': ['alice@example.com', 'bob@company.org', 'charlie@uni.edu', 'carol@test.net']
})

# Contains substring
has_com = df[df['email'].str.contains('.com')]
print(has_com['name'])  # Alice Johnson

# Startswith / endswith
starts_with_a = df[df['name'].str.startswith('A')]
print(starts_with_a)

edu_email = df[df['email'].str.endswith('.edu')]
print(edu_email['name'])  # Charlie Brown

# Regex contains — find org or edu domains
org_or_edu = df[df['email'].str.contains(r'\.(org|edu)$', regex=True)]
print(org_or_edu[['name', 'email']])
TEXT 📖 للعرض فقط
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on your pandas version.

(3) contains مقابل match

الطريقة موقع المطابقة التعبير النمطي (Regex)
contains أي مكان في النص
match من البداية
startswith من البداية ❌ (نص عادي فقط)
endswith من النهاية ❌ (نص عادي فقط)

5. تقسيم / استخراج

(1) تقسيم

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً — قم بتثبيتها محلياً (`pip install pandas`) واتبع الأمثلة. قد تختلف القيم الفعلية بشكل طفيف حسب إصدار pandas الخاص بك.

: تقسيم السلاسل النصية باستخدام split (الصعوبة ⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'name': ['Alice Johnson', 'Bob Smith', 'Charlie Brown'],
    'email': ['alice@example.com', 'bob@company.org', 'charlie@uni.edu']
})

# تقسيم إلى قائمة
print(df['name'].str.split(' '))
# 0    [Alice, Johnson]
# 1    [Bob, Smith]
# 2    [Charlie, Brown]

# تقسيم إلى أعمدة منفصلة
name_split = df['name'].str.split(' ', expand=True)
print(name_split)
#         0        1
# 0   Alice  Johnson
# 1     Bob    Smith
# 2 Charlie    Brown

# تقسيم والاحتفاظ بالجزء الأول فقط
df['first_name'] = df['name'].str.split(' ').str[0]
print(df['first_name'])

# تقسيم البريد الإلكتروني للحصول على النطاق
df['domain'] = df['email'].str.split('@').str[1]
print(df['domain'])
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً — قم بتثبيتها محلياً (`pip install pandas`) واتبع الأمثلة. قد تختلف القيم الفعلية بشكل طفيف حسب إصدار pandas الخاص بك.

(2) استخراج باستخدام التعبيرات النمطية

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً — قم بتثبيتها محلياً (`pip install pandas`) واتبع الأمثلة. قد تختلف القيم الفعلية بشكل طفيف حسب إصدار pandas الخاص بك.

: استخراج الأنماط باستخدام extract (الصعوبة ⭐⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'contact': [
        'Alice <alice@example.com>',
        'Bob <bob@company.org>',
        'Charlie (555-0100)',
        'Carol <carol@test.net>'
    ]
})

# استخراج البريد الإلكتروني باستخدام مجموعة regex
df['email'] = df['contact'].str.extract(r'<(.+?)>')
print(df[['contact', 'email']])
#                   contact             email
# 0  Alice <alice@example.com>  alice@example.com
# 1      Bob <bob@company.org>    bob@company.org
# 2     Charlie (555-0100)                NaN
# 3    Carol <carol@test.net>    carol@test.net

# استخراج مجموعات متعددة
df2 = pd.DataFrame({
    'email': ['alice@example.com', 'bob@company.org']
})
parts = df2['email'].str.extract(r'(.+?)@(.+)')
print(parts)
#        0             1
# 0  alice  example.com
# 1    bob   company.org

# استخراج جميع التطابقات
colors = pd.Series(['red,blue,green', 'yellow,pink'])
print(colors.str.extractall(r'(\w+)'))
TEXT 📖 للعرض فقط
> **الإخراج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً — قم بتثبيتها محلياً (`pip install pandas`) واتبع الأمثلة. قد تختلف القيم الفعلية بشكل طفيف حسب إصدار pandas الخاص بك.

6. طرق شائعة أخرى

(1) مرجع سريع

الطريقة الغرض مثال
len() طول النص s.str.len()
count() عدد مرات ظهور جزء نصي s.str.count('a')
find() موضع جزء نصي s.str.find('bc')
isdigit() هل كلها أرقام؟ s.str.isdigit()
isalpha() هل كلها حروف؟ s.str.isalpha()
join() ربط بفاصل s.str.join(',')
pad() حشو لعرض ثابت s.str.pad(10, fillchar='0')
repeat() تكرار النص s.str.repeat(3)
slice() تقطيع s.str.slice(0, 5)

▶ مثال

TEXT 📖 للعرض فقط
> **المخرج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) وتابع معنا. القيم الفعلية قد تختلف قليلاً حسب إصدار pandas الخاص بك.

: pad/slice/zfill (الصعوبة ⭐)

PYTHON
import pandas as pd

ids = pd.Series(['1', '23', '456', '7890'])

# Pad with zeros to 4 digits
print(ids.str.zfill(4))
# 0    0001
# 1    0023
# 2    0456
# 3    7890

# Slice first 2 characters
codes = pd.Series(['US-001', 'UK-002', 'JP-003'])
print(codes.str.slice(0, 2))  # US, UK, JP
print(codes.str[:2])           # same, Python slice syntax
TEXT 📖 للعرض فقط
> **المخرج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) وتابع معنا. القيم الفعلية قد تختلف قليلاً حسب إصدار pandas الخاص بك.

7. مثال كامل: خط أنظيف لتنظيف بيانات نصية للمستخدم

(5) ▶ سير عمل تنظيف النص

100%
graph TB
    A[النص الخام] --> B[strip: إزالة المسافات البيضاء]
    B --> C[lower / upper: توحيد حالة الأحرف]
    C --> D[replace: إزالة الأحرف الخاصة]
    D --> E[split / extract: استخراج المعلومات]
    E --> F[title: تنسيق المخرجات]
    F --> G[النص النظيف]
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبته مسبقاً — قم بتثبيته محلياً (`pip install pandas`) وتابع التنفيذ. قد تختلف القيم الفعليه قليلاً حسب إصدار pandas الخاص بك.

▶ مثال

TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبته مسبقاً — قم بتثبيته محلياً (`pip install pandas`) وتابع التنفيذ. قد تختلف القيم الفعليه قليلاً حسب إصدار pandas الخاص بك.

: التنظيف الشامل للنهاية إلى النهاية (الصعوبة ⭐⭐⭐)

PYTHON
import pandas as pd

# ============================================
# مثال شامل: خط أنظيف لتنظيف النص
# لبيانات المستخدم
# ============================================

# 1. بيانات المستخدم الخام غير المنسقة
df = pd.DataFrame({
    'raw_name': ['  ALICE johnson  ', 'bob   SMITH', '  CHARLIE! brown  ', 'CAROL white123'],
    'raw_email': ['ALICE@Example.COM', 'bob@company.ORG', 'charlie@uni.EDU', 'CAROL@TEST.NET'],
    'raw_phone': ['555-0100', '(555) 0200', '555.0300 ext 42', '+1-555-0400'],
    'raw_zip': ['0123', '12345', '  90210  ', '10001-2345']
})

# 2. تنظيف الاسم: إزالة المسافات ← إزالة الأحرف الخاصة ← حالة العنوان
df['name'] = (df['raw_name']
    .str.strip()
    .str.replace(r'[^a-zA-Z\s]', '', regex=True)
    .str.replace(r'\s+', ' ', regex=True)  # تقليل المسافات المتعددة
    .str.title()
)

# 3. تنظيف البريد الإلكتروني: أحرف صغيرة
df['email'] = df['raw_email'].str.lower()

# 4. تنظيف رقم الهاتف: الاحتفاظ بالأرقام فقط
df['phone_digits'] = df['raw_phone'].str.replace(r'[^0-9]', '', regex=True)
df['phone_formatted'] = df['phone_digits'].str.slice(0, 3) + '-' + df['phone_digits'].str.slice(3, 7)

# 5. الرمز البريدي: استخراج الرمز المكون من 5 أرقام
df['zip5'] = df['raw_zip'].str.strip().str.extract(r'(\d{5})')

# 6. نطاق البريد الإلكتروني
df['domain'] = df['email'].str.split('@').str[1]

# 7. عرض النتائج المنظفة
print("=== البيانات المنظفة ===")
print(df[['name', 'email', 'phone_formatted', 'zip5', 'domain']])
TEXT 📖 للعرض فقط
> **المخرجات:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبته مسبقاً — قم بتثبيته محلياً (`pip install pandas`) وتابع التنفيذ. قد تختلف القيم الفعليه قليلاً حسب إصدار pandas الخاص بك.

❓ أسئلة شائعة

س ما الفرق بين .str وسلسلة Python str؟
ج تعمل أساليب Python str على سلسلة واحدة، بينما يعمل مُدخل .str على عمود بالكامل (مُتجه). يتخطى مُدخل .str تلقائيًا القيم NaN (مع إرجاع NaN)، بينما تُسبب سلسلة Python str خطأً في حالة NaN. يدعم مُدخل .str تسلسل الأساليب (s.str.strip().str.lower())، وهو ما لا تدعمه سلسلة Python str. من حيث الأداء، يكون .str أسرع بـ 10-100 مرة من التكرار.
س كيف تتم معالجة قيم NaN؟
ج تتخطى أساليب .str تلقائيًا القيم NaN — إذا كان المُدخَل NaN، يكون المُخرَج NaN. لا حاجة للتحقق يدويًا من القيم المفقودة. هذا أحد أسباب كون .str أكثر ملاءمة من استخدام apply + Python str. لاحظ أن contains/match تُرجع False (وليس NaN) للقيم NaN، فضع ذلك في الاعتبار عند التصفية.
س ماذا يُرجع extract؟
ج يُرجع extract إطار بيانات — عمود واحد لكل مجموعة تعبير نمطي. تُنتج مجموعة واحدة إطار بيانات بعمود واحد؛ وتنتج المجموعات المتعددة أعمدة متعددة. يُرجع extractall جميع المطابقات (بفهرس متعدد). ملاحظة: تُرجع الصفوف غير المطابقة NaN. إذا كنت بحاجة إلى سلسلة، استخدم .str.extract(...)[0].
س ما الفرق بين contains و match؟
ج تطابق contains في أي مكان من السلسلة (مثال: 'abc' contains 'b' → True). بينما تطابق match فقط من بداية السلسلة (مثال: 'abc' match 'b' → False). أساليب startswith/endswith هي مقارنات سلاسل نصية بسيطة (بدعم للتعبيرات النمطية). استخدم contains/match عندما تحتاج إلى تعبيرات نمطية، وstartswith/endswith لعمليات التحقق البسيطة من النص.
س ما هي فوائد StringDtype؟
ج بشكل افتراضي، تستخدم أعمدة السلاسل النصية نوع البيانات كائن (كائنات Python)، حيث يكون كل قيمة نسخة منفصلة من str. StringDtype (df['col'].astype('string')) هو نوع Pandas مخصص للسلاسل النصية يستخدم pd.NA للقيم المفقودة، وهو أكثر كفاءة في استخدام الذاكرة، ويقدم سلوك .str أكثر اتساقًا. توصي Pandas 2.x باستخدام StringDtype بدلًا من كائن للبيانات النصية.
س ما الفرق بين str.replace و df.replace؟
ج يعمل str.replace فقط على الأعمدة النصية، ويدعم التعبيرات النمطية (regex=True)، ويُستبدل العنصر بعنصر. يعمل df.replace على إطار البيانات بالكامل، ويمكنه استبدال قيم من أي نوع، ويدعم أيضًا التعبيرات النمطية. للاستبدال النصي، يُفضَّل استخدام str.replace (دلالة أوضح)؛ للاستبدال عبر الأعمدة، استخدم df.replace.
س كيف أستخرج الأرقام من رقم هاتف؟
ج استخدم s.str.replace(r'[^0-9]', '', regex=True) لإزالة جميع الأحرف غير الرقمية. بديلاً عن ذلك، استخدم extract: s.str.extract(r'(\d{3})[-.)\s]*(\d{3})[-.)\s]*(\d{4})') لالتقاط رمز المنطقة والبادئة ورقم الخط بشكل منفصل. التعبيرات النمطية هي الأداة الأساسية لاستخراج النصوص.

📖 ملخص


📝 تمارين

  1. أساسي (الصعوبة ⭐): أنشئ سلسلة (Series) من الأسماء مع مسافات بيضاء إضافية وأحرف غير منتظمة. قم بتنظيفها باستخدام .str.strip().str.title()، ثم احسب عدد الأسماء النظيفة التي تبدأ بحرف 'A'.
  2. متوسط (الصعوبة ⭐⭐): أنشئ سلسلة (Series) من أرقام الهواتف بصيغ مختلطة. استخدم replace مع التعبير النمطي (regex) لاستخراج الأرقام فقط، ثم قم بتنسيقها إلى 10 أحرف باستخدام zfill.
  3. تحدي (الصعوبة ⭐⭐⭐): قم بمحاكاة بيانات تسجيل المستخدمين (الاسم/البريد الإلكتروني/الهاتف/الرمز البريدي جميعها مع مشاكل في التنسيق). قم ببناء خط أنابيب تنظيف من 5 خطوات — طريقة .str واحدة لكل خطوة — وأخرج الجدول النهائي النظيف.

← Previous: Reshaping and Pivoting · Next: Date and Time →

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%