מחרוזת ב-Go היא רצף בתים immutable, בדרך כלל טקסט UTF-8. האופרטורים עובדים על המחרוזת עצמה (+, ==, <, גישה לפי אינדקס, חיתוך), וכל השאר נמצא בחבילה הסטנדרטית strings.
פיצול מחרוזות
| פונקציה | מפצלת לפי | הערות |
|---|---|---|
Split(s, sep) | כל sep | שומרת חלקים ריקים; Split("", ",") מחזירה [""], מחרוזת ריקה אחת |
SplitN(s, sep, n) | לכל היותר n חלקים | החלק האחרון מחזיק את השאר |
SplitAfter(s, sep) | כל sep | שומרת את המפריד בכל חלק |
Fields(s) | רצפים של רווחים לבנים | אף פעם לא מחזירה חלקים ריקים |
FieldsFunc(s, f) | תווים שעבורם f מחזירה true | מפרידים מותאמים |
Cut(s, sep) | רק ה-sep הראשון | מחזירה לפני, אחרי, נמצא (Go 1.18) |
המקרה של Split("", ",") תופס אנשים: קלט ריק נותן slice באורך 1, לא 0. כשמפצלים קלט של משתמש, Fields או בדיקה של s == "" קודם מונעות איבר ריק מדומה.
strings.Cut היא הדרך הנקייה ביותר לפצל key=value, user@host וזוגות דומים. Go 1.24 הוסיפה גם גרסאות איטרטור, strings.SplitSeq ו-strings.FieldsSeq, שמחזירות חלקים אחד אחד בלי לבנות slice.
חיפוש
| פונקציה | מחזירה |
|---|---|
Contains(s, sub) | true אם sub מופיעה ב-s |
ContainsAny(s, chars) | true אם תו כלשהו מ-chars מופיע |
HasPrefix(s, p) / HasSuffix(s, p) | true אם s מתחילה או נגמרת ב-p |
Index(s, sub) | מיקום בבתים של ההתאמה הראשונה, או -1 |
LastIndex(s, sub) | מיקום בבתים של ההתאמה האחרונה, או -1 |
Count(s, sub) | מספר ההתאמות שלא חופפות |
EqualFold(a, b) | שוויון בלי הבחנה בין אותיות גדולות לקטנות |
כל חיפוש מבחין בין אותיות גדולות לקטנות חוץ מ-EqualFold. כדי לחפש בלי הבחנה, המירו את שני הצדדים לאותיות קטנות או השתמשו ב-EqualFold להשוואה של מחרוזות שלמות.
שינוי מחרוזות
מלכודת אחת: Trim, TrimLeft ו-TrimRight מקבלות קבוצת תווים, לא תחילית. strings.TrimLeft("abcab", "ab") מסירה כל a ו-b בהתחלה ומחזירה "cab". כדי להסיר תחילית או סיומת מדויקת, השתמשו ב-TrimPrefix וב-TrimSuffix.
שרשור ו-strings.Builder
+ מחבר מחרוזות, ו-fmt.Sprintf מעצבת ערכים לתוך מחרוזת אחת. שתיהן מקצות מחרוזת חדשה בכל פעם, כי מחרוזות הן immutable. זה בסדר לקומץ פעולות ואיטי בלולאה, שבה כל += מעתיק את כל מה שנבנה עד עכשיו. השתמשו במקום זה ב-strings.Builder:
strings.Builder בערך האפס שלו מוכן לשימוש. הוא מממש את io.Writer, כך ש-fmt.Fprintf כותבת לתוכו ישירות. קראו קודם ל-b.Grow(n) אם אתם יודעים בערך כמה גדולה תהיה התוצאה. אל תעתיקו Builder אחרי שכתבתם לתוכו; העבירו מצביע.
מחרוזות מרובות שורות ו-raw strings
ל-Go יש שני סוגים של ליטרל מחרוזת:
מחרוזות במירכאות כפולות מעבדות תווי escape (\n, \t, \", \\, \u00e9) וחייבות להיכנס בשורה אחת. raw strings בתוך backticks לוקחות הכול כמו שהוא, כולל שורות חדשות, ולכן הן הדרך לכתוב מחרוזות מרובות שורות, ביטויים רגולריים, JSON ונתיבים של Windows. raw string לא יכולה להכיל backtick, ותווי carriage return בתוכה מושמטים. שימו לב שהשאילתה למעלה מתחילה בשורה חדשה, כי הליטרל מתחיל מיד אחרי ה-backtick הפותח.
אורך, גישה לפי אינדקס ותת מחרוזות
len(s) הוא מספר הבתים. s[i] הוא בית, ו-s[i:j] היא תת מחרוזת לפי מיקומים בבתים:
ï ו-é תופסים שני בתים כל אחד, ולכן המחרוזת היא 12 בתים ו-10 תווים. חיתוך לפי בתים בטוח כל עוד המיקומים מגיעים מ-strings.Index או מפונקציה דומה, שמחזירות היסטים בבתים על גבולות של תווים. כדי לקחת "את n התווים הראשונים", המירו קודם ל-[]rune. הדף על runes ו-bytes מסביר UTF-8 לעומק.
מחרוזות הן immutable
אי אפשר לשנות בית במקום: s[0] = 'H' היא שגיאת הידור (cannot assign to s[0] (neither addressable nor a map index expression)). כל פונקציה ב-strings מחזירה מחרוזת חדשה. כדי לערוך, המירו ל-[]byte או ל-[]rune, שנו את ה-slice והמירו בחזרה:
b := []byte("hello")
b[0] = 'H'
s := string(b) // "Hello"
immutability היא גם הסיבה שתת מחרוזות זולות: s[2:5] חולקת זיכרון עם s במקום להעתיק אותו. הצד השני הוא שתת מחרוזת קטנה של מחרוזת ענקית שומרת את כל המחרוזת הענקית בחיים. השתמשו ב-strings.Clone (Go 1.20) כששומרים חתיכה קצרה מקלט גדול.
השוואת מחרוזות
== ו-!= משווים תוכן, ו-<, > משווים בית אחרי בית, וזה סדר אלפביתי ב-ASCII. strings.Compare קיימת אבל כמעט אף פעם לא נחוצה; slices.Sort על []string משתמשת ב-<. למיון טקסט שאינו באנגלית לפי כללי locale, השתמשו ב-golang.org/x/text/collate.
המרה מטיפוסים אחרים
מספרים הופכים למחרוזות עם strconv.Itoa, strconv.FormatFloat או fmt.Sprintf, ומחרוזות הופכות למספרים עם strconv.Atoi ו-strconv.ParseFloat. אל תכתבו string(42): זה מייצר את התו עם ה-code point 42, "*". הדף על המרת טיפוסים מכיל את הטבלה המלאה.
שאלות נפוצות
איך מפצלים מחרוזת ב-Go?
השתמשו ב-strings.Split(s, sep): strings.Split("a,b,c", ",") מחזירה ["a" "b" "c"]. כדי לפצל לפי כל רצף של רווחים לבנים ולהשמיט חלקים ריקים, השתמשו ב-strings.Fields(s). strings.SplitN מגבילה את מספר החלקים, ו-strings.Cut מפצלת פעם אחת סביב המפריד הראשון.
איך כותבים מחרוזת מרובת שורות ב-Go?
השתמשו ב-raw string literal בתוך backticks:
query := `SELECT id, name
FROM users
WHERE active = true`
כל מה שבין ה-backticks נלקח כמו שהוא, כולל שורות חדשות ולוכסנים הפוכים. raw string לא יכולה להכיל backtick.
איך בודקים אם מחרוזת מכילה תת מחרוזת ב-Go?
strings.Contains(s, substr) מחזירה bool. פונקציות קשורות: strings.HasPrefix, strings.HasSuffix, strings.Index (מיקום או -1), strings.ContainsAny (אחד מתוך קבוצת תווים), ו-strings.EqualFold לשוויון בלי הבחנה בין אותיות גדולות לקטנות.
מה הדרך המהירה ביותר לשרשר מחרוזות ב-Go?
לכמה מחרוזות, + מספיק. כשבונים מחרוזת בלולאה, השתמשו ב-strings.Builder: קראו ל-WriteString שוב ושוב ול-String() פעם אחת בסוף. += חוזר בלולאה מעתיק את כל המחרוזת בכל פעם, כך שהוא נעשה איטי ככל שהמחרוזת גדלה. כדי לחבר slice עם מפריד, השתמשו ב-strings.Join.
למה len מחזירה אורך שגוי למחרוזת שלי?
len(s) מחזירה את מספר הבתים, לא התווים. מחרוזות ב-Go הן UTF-8, שבו תווים מחוץ ל-ASCII תופסים 2 עד 4 בתים, ולכן len("héllo") הוא 6. השתמשו ב-utf8.RuneCountInString(s) כדי לקבל את מספר ה-code points של Unicode.