دليل استخراج السلاسل في C | دوال قياسية ومخصصة ودعم بايتات

目次

1. المقدمة

إن التعامل مع السلاسل النصية في لغة C هو أحد المهارات المهمة عند تعلم البرمجة. خصوصًا،استخراج السلسلة النصية (استخراج الجزء الفرعي من السلسلة) يُستخدم كثيرًا عند معالجة البيانات أو تحويل الصيغ.

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

ما يمكن تعلمه في هذه المقالة

من خلال قراءة هذه المقالة، يمكنك اكتساب المهارات التالية.

  • مفهوم أساسي لسلاسل C والرمز النهائي دوره
  • strncpystrchrاستخراج السلاسل الجزئية باستخدام دوال مكتبة القياسية
  • طريقة تنفيذ معالجة السلاسل باستخدام الدالة المخصصة
  • مراعاة الأحرف متعددة البايت (اللغة اليابانية)
  • strtok طريقة تقسيم السلاسل
  • طريقة الحصول على النص قبل وبعد حرف محدد

سنشرح بطريقة سهلة الفهم حتى للمبتدئين، مع تضمين أمثلة على الشيفرة.

لماذا يعتبر استخراج السلاسل النصية في لغة C مهمًا؟

لغة C تتعامل مع السلاسل النصية كـ مصفوفة (مصفوفة من نوع char)، لذا لا يمكن الحصول على جزء من السلسلة بسهولة كما في اللغات عالية المستوى مثل Python أو JavaScript. لذلك، من المهم اختيار الطريقة المناسبة في الحالات التالية.

1. معالجة بيانات الإدخال

على سبيل المثال، عند تحليل بيانات مثل سجلات النظام أو ملفات CSV، قد تحتاج إلى استخراج عناصر محددة.

2. البحث عن كلمة مفتاحية محددة

البحث عن كلمة مفتاحية محددة داخل سلسلة واستخلاص المعلومات التي تسبقها وتليها أمر أساسي لوظيفة البحث واستخراج البيانات.

3. تحسين أمان البرنامج

strncpy باستخدام دوال مثل strncpy بشكل مناسب، يمكنك منع تجاوز سعة الذاكرة (كتابة بيانات تتجاوز حجم الذاكرة). هذا مهم لتجنب مخاطر الأمان.

هيكل المقالة

في هذه المقالة، سنشرح وفق التسلسل التالي.

  1. ما هو سلسلة الأحرف في لغة C؟ المفاهيم الأساسية وأهمية الحرف النهائي
  2. طريقة استخراج جزء من السلسلة في لغة C【الطبعة باستخدام المكتبة القياسية】
  3. طريقة استخراج السلاسل الجزئية في لغة C【الجزء الخاص بالدوال المخصصة】
  4. طريقة استخراج السلاسل حسب ترميز الأحرف
  5. كيفية تقسيم سلسلة نصية في لغة C
  6. مثال تطبيقي: طريقة استخراج ما قبل وما بعد حرف محدد
  7. الملخص
  8. FAQ

هيا نبدأ بالنظر بالتفصيل إلى «ما هي السلاسل النصية في لغة C؟ المفاهيم الأساسية وأهمية حرف النهاية».

2. ما هي سلاسل النص في لغة C؟ المفاهيم الأساسية وأهمية حرف النهاية

2.1 المفهوم الأساسي لسلاسل النص في لغة C

السلسلة هي «مصفوفة من char»

في لغة C، تُعامل السلاسل كـمصفوفة من الأحرف (مصفوفة من نوع char) . على سبيل المثال، الشيفرة التالية هي مثال أساسي لتعريف وعرض السلسلة.

#include <stdio.h>

int main() {
    char str[] = "Hello, World!"; // Define a string literal as an array
    printf("%s ", str); // Output the string
    return 0;
}

في هذا الكود، السلسلة "Hello, World!" تُخزن كمصفوفة من النوع char، وتُطبع بواسطة printf("%s\n", str); .

التركيب الداخلي للسلسلة

السلسلة "Hello" تُخزن في الذاكرة كما يلي.

فهرس012345
نصHello 

في لغة C، حرف خاص يُظهر نهاية السلسلة (حرف null '\0') يُضاف تلقائيًا في النهاية، لذا يصبح طول السلسلة «عدد الأحرف الفعلي + 1» .

2.2 أهمية حرف النهاية (حرف null '

ما هو حرف null؟

'
)

المشكلة في حالة عدم وجود حرف null

حرف null ('\0') هو حرف خاص يُظهر نهاية السلسلة. لفهم التعامل الصحيح مع سلاسل C، يجب أن تدرك وجود هذا الحرف.

#include <stdio.h>

int main() {
    char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; // Explicitly specify the null terminator
    printf("%s ", str);                            // Display correctly
    return 0;
}

في الشيفرة أعلاه، إذا لم يتوفر '\0'، فإن نهاية "Hello" لن تُعترف، وقد يحدث سلوك غير مقصود .

2.3 طريقة تعريف السلسلة بشكل صحيح

كما هو موضح أدناه، إذا نسيت حرف النهاية، قد يتسبب ذلك في سلوك غير طبيعي للذاكرة.

#include <stdio.h>

int main() {
    char str[5] = {'H', 'e', 'l', 'l', 'o'}; // Does not include the null terminator
    printf("%s ", str);                      // May cause unexpected behavior
    return 0;
}

سبب الخطأ

  • printf("%s\n", str);الحرف الفارغ '\0'
  • إذا لم يكن ، فقد يتم إخراج بيانات أخرى في الذاكرة.

الطريقة ① استخدام حرفية السلسلة

الطريقة ② تعريف المصفوفة صراحة

الطريقة الأكثر شيوعًا لتعريف السلسلة هي استخدام حرفية السلسلة.

char str[] = "Hello";

في هذه الطريقة، يضيف مترجم C حرف null '\0' تلقائيًا، لذا لا حاجة لمعالجة خاصة.

2.4 طريقة التحقق من حجم السلسلة

إذا كنت تريد تعريفًا يدويًا يتضمن '\0'، فستكتب كما يلي.

char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
  • يجب تحديد حجم عدد الأحرف ، ومن ثم وضع في النهاية.
  • إذا نسيت إدخال في ، سيحدث سلوك غير متوقع.

عمل strlen

للحصول على طول السلسلة (عدد الأحرف)، استخدم الدالة strlen .

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello";
    printf("Length of the string: %lu\n", strlen(str)); // Outputs 5 (does not include the null terminator)
    return 0;
}

2.5 الخلاصة

  • strlenالحرف الفارغ '\0' يحسب عدد الأحرف حتى ظهور
  • sizeof(str)
年収訴求

3. طريقة استخراج جزء من السلسلة في C gengo【قسم hyoujun raiburari】

  1. سلاسل النص في لغة C يتم تمثيلها بواسطة مصفوفات char
  2. الرمز النهائي(الرمز الفارغ '\0')يُظهر نهاية السلسلة، لذا يجب دائمًا تضمينه
  3. للحصول على طول سلسلة strlen استخدم
  4. إذا لم تُعرّف السلسلة بطريقة مناسبة، فقد يحدث خطأ غير متوقع.

3.1 الحصول على جزء من السلسلة باستخدام strncpy

لاستخراج جزء من السلسلة في C gengo، هناك طريقة باستخدام مكتبة hyoujun raiburari. في هذا القسم، سنشرح كيفية الحصول على جزء من السلسلة باستخدام strncpy و strchr وغيرها من دوال مكتبة hyoujun raiburari

البنية الأساسية لـ strncpy

strncpy هو دالة تقوم بنسخ جزء من السلسلة إلى مخزن مؤقت آخر .

مثال أساسي للاستخدام

char *strncpy(char *dest, const char *src, size_t n);
  • dest
  • src
  • n'\0'

نقاط الانتباه لـ strncpy

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, World!";
    char dest[6];  // Buffer to store the substring

    strncpy(dest, src, 5); // Copy the first 5 characters "Hello"
    dest[5] = '\0';        // Manually add the null terminator

    printf("Substring: %s\n", dest);  // Output "Hello"

    return 0;
}

3.2 النسخ الآمن للسلسلة باستخدام strncpy_s

  1. الرمز الفارغ '\0' يجب إضافته يدويًاstrncpyn'\0' لا يضيف تلقائيًا، dest[n] = '\0';
  2. احذر من تجاوز حدود الذاكرة المؤقتةdestn

البنية الأساسية لـ strncpy_s

strncpy_s هو نسخة محسّنة من strncpy تُعزز الأمان وتمنع تجاوز سعة المخزن المؤقت.

مثال على الاستخدام

errno_t strncpy_s(char *dest, rsize_t destsz, const char *src, rsize_t n);
  • dest
  • destszdest
  • src
  • n

مزايا strncpy_s

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, World!";
    char dest[6];

    if (strncpy_s(dest, sizeof(dest), src, 5) == 0) {
        dest[5] = '\0';  // Add null terminator just in case
        printf("Substring: %s\n", dest);
    } else {
        printf("Copy error\n");
    }

    return 0;
}

3.3 استخراج حتى حرف معين باستخدام strchr

  • حجم المخزن المؤقت () لتحديده، يمكن النسخ بأمان.
  • إذا كان أكبر من ، فارجع خطأ。

مع ذلك، strncpy_s أضيف في معيار C11، وبالتالي قد لا يكون متاحًا في بعض البيئات.

البنية الأساسية لـ strchr

strchr باستخدامه يمكنك العثور على موقع حرف معين والحصول على السلسلة حتى ذلك الجزء.

مثال على الاستخدام

char *strchr(const char *str, int c);
  • str
  • cchar

نقطة

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, World!";
    char *pos = strchr(str, ','); // Find the position of ','

    if (pos != NULL) {
        int length = pos - str; // Calculate the number of characters up to ','
        char result[20];

        strncpy(result, str, length);
        result[length] = '\0'; // Add the null terminator

        printf("Substring: %s\n", result);  // Output "Hello"
    }

    return 0;
}

3.4 البحث عن كلمة مفتاحية واستخراجها باستخدام strstr

  • strchrالعنوان الأول الذي تم العثور عليه c العنوان
  • pos - strstrncpy

البنية الأساسية لـ strstr

strstr مفيد للبحث عن جزء من السلسلة والحصول على السلسلة التي تليه.

مثال على الاستخدام

char *strstr(const char *haystack, const char *needle);
  • سلة حشائش
  • needle

نقطة

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, World!";
    char *pos = strstr(str, "World"); // Search for the position of "World"

    if (pos != NULL) {
        printf("Found substring: %s\n", pos);
    } else {
        printf("Substring not found.\n");
    }

    return 0;
}

3.5 خلاصة

  • strstrneedle
  • NULLneedlehaystack

4. طريقة استخراج السلسلة الفرعية في لغة C【جزء الدوال المخصصة】

  1. strncpy، باستخدامه يمكنك نسخ الجزء الفرعي بأمان، لكن يجب إضافة الحرف NULL يدويًا。
  2. strncpy_s يمكن أن يحدد destsz__، مما يحسن الأمان。
  3. strchr إذا استخدمت، يمكنك الحصول على الجزء الجزئي من السلسلة حتى حرف محدد。
  4. strstr إذا استخدمت، يمكنك الحصول على موقع كلمة مفتاحية محددة ثم قص الجزء من هناك。

باستخدام مكتبة hyoujun raiburari، يمكنك تنفيذ معالجة السلاسل في C gengo بشكل بسيط وآمن.

4.1 فوائد إنشاء الدوال المخصصة

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

4.2 دالة استخراج السلسلة الفرعية الأساسية

باستخدام مكتبة القياسية، يمكن نسخ السلسلة الجزئية والبحث فيها، لكن توجد المشكلات التالية.

  • strncpy لا يضيف حرف NULL '\0' تلقائيًا
  • strchr و strstr لا يمكنهما سوى البحث الجزئي
  • من الصعب التعامل مع السلاسل النصية بطريقة أكثر مرونة

لذلك، من الفعّال إنشاء دوال مخصصة يمكن تخصيصها وفقًا للاستخدام المحدد.

مواصفات الدالة

أولاً، سننشئ دالة أساسية لاقتطاع السلسلة من الموضع المحدد.

كود التنفيذ

  • المعامل
  • const char *source
  • int start
  • int length
  • char *dest
  • محتوى المعالجة
  • بدءطولالوجهة
  • '\0'

نقاط

#include <stdio.h>
#include <string.h>

void substring(const char *source, int start, int length, char *dest) {
    int i;
    for (i = 0; i < length && source[start + i] != '\0'; i++) {
        dest[i] = source[start + i];
    }
    dest[i] = '\0'; // Add null terminator
}

int main() {
    char text[] = "Hello, World!";
    char result[10];

    substring(text, 7, 5, result); // Extract "World"
    printf("Substring: %s\n", result);

    return 0;
}

4.3 malloc الحصول على السلسلة الفرعية ديناميكيًا باستخدامها

  • forlength
  • '\0'
  • dest[i] = '\0';ضع دائمًا حرف NULL في النهاية

مواصفات الدالة

في الدالة السابقة، يجب حجز حجم dest مسبقًا. ومع ذلك، إذا تم حجز الحجم المطلوب ديناميكيًا، ستصبح الدالة أكثر شمولية.

كود التنفيذ

  • الذاكرة المطلوبة تُحجز باستخدام
  • startlength
  • في الدالة المندوبة يجب

نقاط

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *substring_dynamic(const char *source, int start, int length) {
    char *dest = (char *)malloc(length + 1); // +1 for the null terminator
    if (dest == NULL) {
        return NULL; // Memory allocation failed
    }

    int i;
    for (i = 0; i < length && source[start + i] != '\0'; i++) {
        dest[i] = source[start + i];
    }
    dest[i] = '\0';

    return dest;
}

int main() {
    char text[] = "Hello, World!";
    char *result = substring_dynamic(text, 7, 5);

    if (result != NULL) {
        printf("Substring: %s\n", result);
        free(result); // Free allocated memory
    } else {
        printf("Memory allocation failed.\n");
    }

    return 0;
}

4.4 دعم الأحرف متعددة البايت (اليابانية)

  • mallocتخصيص الذاكرة ديناميكيًا
  • بعد الاستخدام، يجب تحرير الذاكرة باستخدام free(result);

تنفيذ يأخذ في الاعتبار الأحرف متعددة البايت

عند التعامل مع اليابانية (أحرف متعددة البايت مثل UTF-8)، لا يُضمن أن الحرف الواحد يساوي 1 بايت، لذا فإن الدالة البسيطة substring لا تعمل بشكل صحيح.

كود التنفيذ (دعم UTF-8)

  • mbstowcswchar_t
  • wcsncpy
  • wcstombs

نقاط

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <locale.h>

void substring_utf8(const char *source, int start, int length, char *dest) {
    setlocale(LC_ALL, ""); // Set the locale

    wchar_t wsource[256];
    mbstowcs(wsource, source, 256); // Convert UTF-8 string to wide-character string

    wchar_t wresult[256];
    wcsncpy(wresult, wsource + start, length); // Extract substring in wide characters
    wresult[length] = L'\0';

    wcstombs(dest, wresult, 256); // Convert back to multibyte string
}

int main() {
    char text[] = "こんにちは、世界!"; // UTF-8 string
    char result[20];

    substring_utf8(text, 5, 3, result); // Extract "世界"
    printf("Substring: %s\n", result);

    return 0;
}

4.5 الخلاصة

  • setlocale(LC_ALL, "");
  • mbstowcs
  • wcsncpywcstombs

5. طريقة استخراج السلاسل النصية حسب ترميز الأحرف

  1. substring إذا قمت بإنشائه بنفسك، يمكنك الحصول على أجزاء النص بشكل مرن。
  2. باستخدام تخصيص الذاكرة الديناميكية (malloc)، يمكن الحصول على سلسلة جزئية ذات حجم متغير。
  3. عند التعامل مع الأحرف متعددة البايت (اليابانية)، mbstowcs / wcstombs يُستَخدم。

عندما يكون من الصعب التعامل مع مكتبة القياسية مثل strncpy أو strchr، يمكن من خلال إنشاء دوال مخصصة جعل معالجة السلاسل في لغة C أقوى.

5.1 في حالة ASCII(حرف بايت واحد)

في لغة C،إذا لم تُعِر اهتمامًا لاختلافات ترميز الأحرف، قد لا تعمل عملية استخراج السلسلة النصية بشكل صحيح قد يحدث ذلك. على وجه الخصوص، عند التعامل مع أحرف متعددة البايت مثل اللغة اليابانية (UTF-8، Shift_JIS، EUC-JP وغيرها)، لا يكون 1 حرف = 1 بايت، لذا لا يمكن للوظائف البسيطة مثل strncpy أو substring معالجة ذلك بشكل مناسب.

في هذا القسم،طريقة استخراج السلاسل النصية حسب ترميز الأحرف سيتم شرحها بالتفصيل.

استخراج الجزء الفرعي الأساسي

مثال على التنفيذ

حرف ASCII هو 1 حرف = 1 بايت، لذا يمكن مع وظائف strncpy أو substring معالجته بسهولة.

5.2 في حالة UTF-8(أحرف متعددة البايت)

#include <stdio.h>
#include <string.h>

void substring_ascii(const char *source, int start, int length, char *dest) {
    strncpy(dest, source + start, length);
    dest[length] = '\0'; // Add null terminator
}

int main() {
    char text[] = "Hello, World!";
    char result[6];

    substring_ascii(text, 7, 5, result); // Extract "World"
    printf("Substring: %s\n", result);

    return 0;
}

نقطة

  • في حالة الأحرف ASCII (الأرقام والحروف فقط) strncpy يكفي التعامل
  • '\0'(الرمز الصفري)يجب دائمًا إضافته

خصائص UTF-8

طريقة المعالجة الصحيحة

في UTF-8، عدد البايتات لكل حرف يتراوح بين 1-4 بايت ويتغير، لذا إذا استُخدم strncpy ببساطة قد يتم قطع الحرف في منتصفه.

استخراج الجزء الفرعي المتوافق مع UTF-8

في لغة C، لمعالجة UTF-8 بأمان يجب استخدام mbstowcs لتحويله إلى سلسلة عريضة ( wchar_t ) ، ثم يُنصح بطريقة استخراج الجزء الفرعي.

5.3 في حالة Shift_JIS(أحرف متعددة البايت)

#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>

void substring_utf8(const char *source, int start, int length, char *dest) {
    setlocale(LC_ALL, ""); // Set the locale

    wchar_t wsource[256];
    mbstowcs(wsource, source, 256); // Convert multibyte string to wide-character string

    wchar_t wresult[256];
    wcsncpy(wresult, wsource + start, length); // Get the substring
    wresult[length] = L'\0';

    wcstombs(dest, wresult, 256); // Convert wide-character string back to multibyte
}

int main() {
    char text[] = "こんにちは、世界!"; // UTF-8 string
    char result[20];

    substring_utf8(text, 5, 3, result); // Extract "世界"
    printf("Substring: %s\n", result);

    return 0;
}

نقطة

  • setlocale(LC_ALL, "");
  • باستخدام سلسلة متعددة البايت إلى ، معالجتها بأمان باستخدام 。
  • wcstombs

خصائص Shift_JIS

استخراج الجزء الفرعي المتوافق مع Shift_JIS

في Shift_JIS، 1 حرف قد يكون 1 بايت أو 2 بايت، لذا فإن الاستخدام البسيط لـ strncpy قد يسبب تشويهاً في النص.

تنفيذ في Shift_JIS

حتى في حالة Shift_JIS، طريقة تحويل إلى سلسلة عريضة ومعالجتها يُنصح بها.

5.4 في حالة EUC-JP(أحرف متعددة البايت)

#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>

void substring_sjis(const char *source, int start, int length, char *dest) {
    setlocale(LC_ALL, "Japanese"); // Set locale to handle Shift_JIS

    wchar_t wsource[256];
    mbstowcs(wsource, source, 256); // Convert multibyte string (Shift_JIS) to wide-character string

    wchar_t wresult[256];
    wcsncpy(wresult, wsource + start, length); // Extract substring
    wresult[length] = L'\0';

    wcstombs(dest, wresult, 256); // Convert wide-character string back to multibyte (Shift_JIS)
}

int main() {
    char text[] = "こんにちは、世界!"; // Shift_JIS string (depending on environment)
    char result[20];

    substring_sjis(text, 5, 3, result); // Extract "世界"
    printf("Substring: %s\n", result);

    return 0;
}

نقطة

  • للتعامل مع Shift_JIS بشكل صحيح، قم بتعيين 。
  • mbstowcswcstombs

خصائص EUC-JP

استخراج الجزء الفرعي المتوافق مع EUC-JP

EUC-JP، مثل Shift_JIS، يختلف عدد البايتات لكل حرف، لذا فإن التحويل باستخدام أحرف عريضة مطلوب .

5.5 ملخص

#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>

void substring_eucjp(const char *source, int start, int length, char *dest) {
    setlocale(LC_ALL, "ja_JP.eucJP"); // Set locale to handle EUC-JP

    wchar_t wsource[256];
    mbstowcs(wsource, source, 256); // Convert multibyte string (EUC-JP) to wide-character string

    wchar_t wresult[256];
    wcsncpy(wresult, wsource + start, length); // Extract substring
    wresult[length] = L'\0';

    wcstombs(dest, wresult, 256); // Convert wide-character string back to multibyte (EUC-JP)
}

int main() {
    char text[] = "こんにちは、世界!"; // EUC-JP string (depending on environment)
    char result[20];

    substring_eucjp(text, 5, 3, result); // Extract "世界"
    printf("Substring: %s\n", result);

    return 0;
}

نقطة

  • setlocale(LC_ALL, "ja_JP.eucJP");
  • استخدم / لمعالجة الأحرف متعددة البايت بشكل صحيح.

6. طريقة تقسيم السلاسل في لغة C

رمز الأحرفعدد البايتاتالطريقة الموصى بها للمعالجة
ASCII1 بايتstrncpy
UTF-81-4 بايتmbstowcswcstombs
Shift_JIS1 or 2 بايتmbstowcswcstombs
EUC-JP1 أو 2 بايتmbstowcswcstombs
  • ASCII إذا كان فقط نص strncpy مقبول
  • في حالة UTF-8، Shift_JIS، EUC-JP، استخدم mbstowcs / wcstombs
  • حسب البيئة setlocale(LC_ALL, \"...\"); ضبطها بشكل مناسب

6.1 تقسيم السلاسل باستخدام strtok

معالجة تقسيم السلاسل، تحليل بيانات CSV، ومعالجة وسائط سطر الأوامر، وتحليل بيانات السجلات إلخ، ضرورية في العديد من الحالات. في لغة C، هناك طرق لاستخدام دوال مكتبة القياسية مثل strtok و strtok_r، أو إنشاء دوال مخصصة.

في هذا القسم، طريقة تقسيم السلاسل باستخدام حرف فاصل محدد سيتم شرحها بالتفصيل.

الصيغة الأساسية

strtok هو دالة تقوم بتقسيم السلاسل باستخدام حرف الفاصل المحدد (المحدد).

مثال الاستخدام: تقسيم السلاسل باستخدام الفاصلة ,

char *strtok(char *str, const char *delim);
  • str
  • delim
  • قيمة الإرجاع
  • نقاط يجب الانتباه إليهاstrtok'\0'

نتيجة التنفيذ

#include <stdio.h>
#include <string.h>


int main() {
    char str[] = "apple,banana,orange,grape"; // String to be split
    char *token = strtok(str, ",");            // Get the first token

    while (token != NULL) {
        printf("Token: %s\n", token);
        token = strtok(NULL, ",");             // Get the next token
    }

    return 0;
}

نقاط الانتباه لـ strtok

token: apple
token: banana
token: orange
token: grape

6.2 تقسيم السلاسل الآمن للمتعدد الخيوط باستخدام strtok_r

  1. تغيير السلسلة الأصلية
  • strtok حرف الفاصل يُستبدل بـ '\0' ،
  1. غير thread-safe
  • strtokيستخدم متغيرات ثابتة عالمية داخليًا

الصيغة الأساسية

strtok_r هو النسخة الآمنة للمتعدد الخيوط من strtok، حيث يتم حفظ الحالة في saveptr، وبالتالي يمكن استخدامه بأمان في بيئات متعددة الخيوط.

مثال الاستخدام: تقسيم السلاسل باستخدام المسافة

char *strtok_r(char *str, const char *delim, char **saveptr);
  • str
  • delim
  • saveptr

مزايا strtok_r

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello World from C"; // String to be split
    char *token;
    char *saveptr; // Pointer to store internal state

    token = strtok_r(str, " ", &saveptr); // Get the first token
    while (token != NULL) {
        printf("Token: %s\n", token);
        token = strtok_r(NULL, " ", &saveptr); // Get the next token
    }

    return 0;
}

6.3 تقسيم السلاسل باستخدام دالة مخصصة (طريقة لا تستخدم strtok)

  • آمن الخيوط
  • يمكن معالجة عدة سلاسل نصية بالتوازي

مواصفات الدالة المخصصة

strtok يغيّر السلسلة الأصلية، لذا يمكن إنشاء دالة مخصصة لتقسيم السلاسل دون تعديلها.

كود التنفيذ

  • إدخال
  • const char *source
  • const char delim
  • char tokens[][50]
  • معالجة
  • source
  • delimtokens

نتيجة التنفيذ

#include <stdio.h>
#include <string.h>

void split_string(const char *source, char delim, char tokens[][50], int *count) {
    int i = 0, j = 0, token_index = 0;

    while (source[i] != '\0') {
        if (source[i] == delim) {
            tokens[token_index][j] = '\0';
            token_index++;
            j = 0;
        } else {
            tokens[token_index][j] = source[i];
            j++;
        }
        i++;
    }
    tokens[token_index][j] = '\0';
    *count = token_index + 1;
}

int main() {
    char text[] = "dog,cat,bird,fish";
    char tokens[10][50]; // Can store up to 10 words
    int count;

    split_string(text, ',', tokens, &count);

    for (int i = 0; i < count; i++) {
        printf("Token: %s\n", tokens[i]);
    }

    return 0;
}

نقاط مهمة

Token: dog
Token: cat
Token: bird
Token: fish

6.4 تطبيقات تقسيم السلاسل (معالجة بيانات CSV)

  • source
  • tokens

مثال على تحليل بيانات CSV

يمكن تحليل بيانات CSV (مفصولة بفواصل) باستخدام strtok.

نتيجة التنفيذ

#include <stdio.h>
#include <string.h>

int main() {
    char csv[] = "Alice,24,Female\nBob,30,Male\nCharlie,28,Male"; // CSV data
    char *line = strtok(csv, "\n"); // Process line by line

    while (line != NULL) {
        char *name = strtok(line, ",");
        char *age = strtok(NULL, ",");
        char *gender = strtok(NULL, ",");

        printf("Name: %s, Age: %s, Gender: %s\n", name, age, gender);

        line = strtok(NULL, "\n");
    }

    return 0;
}

6.5 الخلاصة

Name: Alice, Age: 24, Gender: Female
Name: Bob, Age: 30, Gender: Male
Name: Charlie, Age: 28, Gender: Male

الاستنتاج

طريقةمزاياالعيوب
strtokيمكن تقسيمه بسهولةتغيير السلسلة الأصلية
strtok_rآمن من حيث الخيوطالطريقة لاستخدامها معقدة قليلاً
دالة مخصصةلا تقم بتغيير السلسلة الأصليةالكود يصبح طويلاً
تحليل CSVمفيد لمعالجة البياناتstrtok احذر القيود

7. مثال تطبيقي: طريقة استخراج ما قبل وما بعد حرف معين

  • إذا كان التقسيم بسيطًا strtok
  • إذا كان متعدد الخيوط strtok_r
  • إذا كنت لا تريد تغيير الأصل، استخدم دالة مخصصة
  • يمكن تطبيقه أيضًا على تحليل بيانات CSV

في القسم التالي، سنشرح بالتفصيل 「مثال تطبيقي: طريقة استخراج الأحرف قبل وبعد حرف معين」.

7.1 strchr للحصول على السلسلة التي تسبق حرفًا معينًا

في معالجة السلاسل النصية،استخراج ما قبل وما بعد حرف أو كلمة مفتاحية معينةغالبًا ما يكون ذلك مطلوبًا. على سبيل المثال، يمكن التفكير في الحالات التالية.

  • الحصول على الجزء المخصص للمجال فقط من URL
  • استخراج اسم الملف من مسار الملف
  • الحصول على السلسلة قبل وبعد العلامات أو الرموز المحددة

في لغة C،strchr و strstr يمكن استخدامها لتحقيق هذه المعالجة. بالإضافة إلى ذلك، إذا كانت هناك حاجة لمعالجة أكثر مرونة، فإن إنشاء دوال مخصصة يعتبر خيارًا فعالًا.

الصيغة الأساسية

strchr باستخدامه، يمكن تحديد موقع حرف (الأول الذي يُعثر عليه).

مثال الاستخدام: استخراج اسم الملف من مسار الملف

char *strchr(const char *str, int c);
  • str
  • cchar

strchr إذا وجدت c، تُعيد عنوانه.

نتيجة التنفيذ

#include <stdio.h>
#include <string.h>

void get_filename(const char *path, char *filename) {
    char *pos = strrchr(path, '/'); // Search for the last '/'

    if (pos != NULL) {
        strcpy(filename, pos + 1); // Copy from the character after '/'
    } else {
        strcpy(filename, path); // If no '/', copy the whole path
    }
}

int main() {
    char path[] = "/home/user/documents/report.txt";
    char filename[50];

    get_filename(path, filename);
    printf("Filename: %s\n", filename);

    return 0;
}

نقطة مهمة

Filename: report.txt

7.2 strstr للحصول على السلسلة التي تلي كلمة مفتاحية معينة

  • strrchr يمكنك الحصول على موقع الحرف المحدد الذي ظهر آخر مرة (/)
  • pos + 1اسم الملف فقط

الصيغة الأساسية

strstr باستخدامه، يمكن البحث عن سلسلة معينة (كلمة مفتاحية) والحصول على السلسلة التي تلي موقعها.

مثال الاستخدام: استخراج النطاق من URL

char *strstr(const char *haystack, const char *needle);
  • haystack
  • needle

strstr إذا وجدت needle، تُعيد عنوان موقعها.

نتيجة التنفيذ

#include <stdio.h>
#include <string.h>

void get_domain(const char *url, char *domain) {
    char *pos = strstr(url, "://"); // Search for the position of "://"

    if (pos != NULL) {
        strcpy(domain, pos + 3); // Copy from the character after "://"
    } else {
        strcpy(domain, url); // If "://" is not found, copy the entire string
    }
}

int main() {
    char url[] = "https://www.example.com/page.html";
    char domain[50];

    get_domain(url, domain);
    printf("Domain part: %s\n", domain);

    return 0;
}

نقطة مهمة

Domain part: www.example.com/page.html

7.3 strchr لتقسيم الجزء قبل وبعد حرف معين

  • strstr"https://""http://""//"
  • pos + 3://

مثال الاستخدام: فصل اسم المستخدم والنطاق من عنوان البريد الإلكتروني

strchr باستخدامه، يمكن تقسيم السلسلة إلى جزأين قبل وبعد الحرف المحدد والحصول عليهما.

نتيجة التنفيذ

#include <stdio.h>
#include <string.h>

void split_email(const char *email, char *username, char *domain) {
    char *pos = strchr(email, '@'); // Search for the position of '@'

    if (pos != NULL) {
        strncpy(username, email, pos - email); // Copy the part before '@'
        username[pos - email] = '\0';          // Add null terminator
        strcpy(domain, pos + 1);               // Copy the part after '@'
    }
}

int main() {
    char email[] = "user@example.com";
    char username[50], domain[50];

    split_email(email, username, domain);
    printf("Username: %s\n", username);
    printf("Domain: %s\n", domain);

    return 0;
}

نقطة مهمة

Username: user
Domain: example.com

7.4 تطبيق: استخراج خاصية معينة داخل وسم HTML

  • strchr'@'
  • strncpy'@' الجزء قبله، نسخ، وإضافة حرف NULL
  • strcpy'@'

مثال الاستخدام: <a href="URL"> استخراج URL

عند استخراج خاصية معينة من داخل وسم HTML، يمكن أيضًا الاستفادة من strstr.

نتيجة التنفيذ

#include <stdio.h>
#include <string.h>

void get_href(const char *html, char *url) {
    char *start = strstr(html, "href=\""); // Search for the position of href="
    if (start != NULL) {
        start += 6; // Move past href="
        char *end = strchr(start, '"'); // Search for the next "
        if (end != NULL) {
            strncpy(url, start, end - start);
            url[end - start] = '\0'; // Add null terminator
        }
    }
}

int main() {
    char html[] = "<a href=\"https://example.com\">Click Here</a>";
    char url[100];

    get_href(html, url);
    printf("Extracted URL: %s\n", url);

    return 0;
}

نقطة مهمة

Extracted URL: https://example.com

7.5 الخلاصة

  • strstr"href=\""
  • strchr"

الاستنتاج

محتوى المعالجةاستخدام الدالةمزايا
الحصول على ما قبل حرف محددstrchr / strrchrبسيط وسريع
الحصول على ما بعد حرف محددstrstrيمكن البحث بالكلمات الرئيسية
تقسيم قبل وبعد باستخدام حرف محددstrchr + strncpyمفيد لتقسيم اسم المستخدم والنطاق وما إلى ذلك
الحصول على سمات علامة HTMLstrstr + strchrقابل للتطبيق على استخراج الويب

8. الملخص

  • strchr و strstr، يمكنك بسهولة الحصول على ما قبل وما بعد حرف أو كلمة مفتاحية محددة
  • معالجة مسارات الملفات، تحليل عناوين URL، تقسيم عناوين البريد الإلكتروني، وما إلى ذلك، مفيدة في العديد من الحالات。
  • قابل للتطبيق حتى على عمليات متقدمة مثل استخراج البيانات من الويب

8.1 مراجعة المقالة

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

8.2 الطريقة المثلى حسب الاستخدام

القسمالمحتوىنقاط مهمة
أساسيات سلاسل النص في لغة Cفي لغة C، يُعامل السلسلة كـ مصفوفة، ويُعتبر حرف النهاية مهمًاعند التعامل مع السلاسل النصية، لا تنسَ النهاية بالـ null
استخراج من المكتبة القياسيةstrncpystrchrstrncpyيجب إضافة النهاية الصفرية يدويًا
استخراج باستخدام دالة مخصصةإنشاء دالة مرنةmalloc يمكن استخراج جزء من السلسلة بطول متغير
معالجة حسب رمز الأحرفكيفية التعامل مع UTF-8، Shift_JIS، EUC-JPmbstowcswcstombsتحويل إلى أحرف واسعة آمن
طريقة تقسيم السلسلةstrtokstrtok_rstrtokيغير السلسلة الأصلية
استخراج الأحرف قبل وبعد حرف محددstrchrstrstrالحصول على أسماء الملفات، تحليل URL، تحليل HTML

1. استخراج جزء من السلسلة

2. تقسيم السلسلة

حالة الاستخدامالطريقة المثلى
أريد الحصول على سلسلة بطول معينstrncpy or substring()
أريد إجراء استخراج آمنstrncpy_s
التعامل مع الأحرف متعددة البايت (UTF-8, Shift_JIS, EUC-JP)mbstowcs / wcstombs

3. الحصول على ما قبل وما بعد حرف معين

حالة الاستخدامالطريقة المثلى
أريد تقسيم السلسلة ببساطةstrtok
أريد تقسيم آمن من حيث الخيوطstrtok_r
أريد تقسيم دون تغيير السلسلة الأصليةدالة مخصصة(split_string()

8.3 ملاحظات حول معالجة السلاسل النصية في لغة C

حالة الاستخدامالطريقة المثلى
الحصول على اسم الملف من مسار الملفstrrchr(path, '/')
الحصول على الجزء المعياري من عنوان URLstrstr(url, "://")
افصل اسم المستخدم والنطاق من عنوان البريد الإلكترونيstrchr(email, '@')
الحصول على قيم السمات من وسوم HTMLstrstr(tag, "href=\"") + strchr(tag, '"')

1. التأكد من إدارة النهاية الصفرية '
مثال على نسخ السلسلة بأمان
'

2. الانتباه إلى تجاوز سعة الذاكرة المؤقتة

في معالجة السلاسل النصية بلغة C، حرف النهاية '\0' بشكل مناسب هو الأكثر أهمية . خاصةً عند استخدام strncpy أو strchr، يجب الانتباه إلى إضافة حرف الصفر يدوياً .

3. استخدم mbstowcs لمعالجة الأحرف متعددة البايت

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, World!";
    char dest[6];

    strncpy(dest, src, 5);
    dest[5] = '\0'; // Add null terminator for safety

    printf("Substring: %s\n", dest);

    return 0;
}

4. إدارة حجم الذاكرة المؤقتة

في عمليات السلاسل النصية بلغة C، يجب تنفيذها بحذر لتجنب الوصول إلى خارج حدود المصفوفة. خاصةً عند استخدام strncpy، من المهم التحكم في عدد البايتات المنسوخة .

مثال على نسخ السلسلة بأمان

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, World!";
    char dest[6];

    strncpy(dest, src, sizeof(dest) - 1);
    dest[5] = '\0'; // Explicitly add null terminator

    printf("Substring: %s\n", dest);
    return 0;
}

8.4 نحو تعلم أعمق

عند التعامل مع الأحرف متعددة البايت مثل UTF-8 أو Shift_JIS، لا تعمل strncpy أو strlen بشكل صحيح.

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

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main() {
    setlocale(LC_ALL, ""); // Set the locale

    char text[] = "こんにちは、世界!"; // UTF-8
    wchar_t wtext[256];

    mbstowcs(wtext, text, 256); // Convert to wide-character string

    printf("Converted wide-character string: %ls\n", wtext);

    return 0;
}

مواضيع لتعميق التعلم

في معالجة السلاسل النصية، من المهم حساب حجم الذاكرة المطلوب مسبقاً ومنع تجاوز سعة الذاكرة المؤقتة. خاصةً عند استخدام malloc لتخصيص الذاكرة الديناميكية، يجب التأكد من معرفة الحجم بدقة.

8.5 الخلاصة

معالجة السلاسل النصية في لغة C هي مهارة مهمة لتحسين أمان البرنامج وقابليته للقراءة. بناءً على ما تم تقديمه في هذه المقالة، سيمكنك تعلم المواضيع التالية للوصول إلى معالجة سلاسل نصية أكثر تقدماً.

مواضيع لتعميق التعلم

  1. التعبير النمطي (regex)
  2. العمليات على الملفات(معالجة السلاسل باستخدام fgets, fscanf)
  3. إدارة الذاكرة (معالجة السلاسل النصية الديناميكية باستخدام malloc, realloc)
  4. تحليل البيانات (طريقة تحليل JSON, XML)

8.5 الخلاصة

  1. سلاسل النص في لغة C char مصفوفة تُدار، لذلك، حرف النهاية '\0' التعامل معها مهم
  2. لاستخراج السلاسل الجزئية باستخدام strncpy, substring(), malloc
  3. لتحليل السلاسل النصية strtok / strtok_r / استخدام الدوال المخصصة
  4. عند رغبتك في الحصول على الأحرف قبل وبعد حرف محدد strchr, strstr استخدم
  5. عند التعامل مع الأحرف متعددة البايت (اليابانية)، mbstowcs استخدم
  6. احرص على معالجة السلاسل النصية بأمان، وكن حذرًا من تجاوز حدود المخزن المؤقت

إذا استفدت من محتوى هذه المقالة، ستتمكن من تنفيذ معالجة سلاسل نصية عملية في لغة C. بعد فهم الدوال الأساسية، تحدى نفسك بإنشاء دوال خاصة ومعالجات متقدمة لتكتب شيفرة أكثر كفاءة!

侍エンジニア塾