אינטרפולציה של מחרוזת

בתכנות מחשב, אינטרפולציה של מחרוזת (באנגלית: String interpolation) היא תהליך של פענוח מחרוזת מילולית המכילה שומרי מקום, המספקת תוצאה שבה שומרי המקום מוחלפים בערכים המתאימים להם. זוהי צורה של עיבוד תבנית פשוט<ref>"[http://www.cs.usfca.edu/~parrt/papers/mvc.templates.pdf Enforcing Strict Model-View Separation in Template Engines]", T. Parr (2004), WWW2004 conference.</ref> או, במונחים פורמליים, צורה של קוואזי ציטוט (או החלפה לוגית). שומר המקום עשוי להיות שם משתנה, או בשפות מסוימות ביטוי שרירותי, שמפוענח בהקשר הנוכחי.

אינטרפולציה של מחרוזת היא אלטרנטיבה לבניית מחרוזת באמצעות שרשור, הדורשת פתיחת וסגירת מירכאות שוב ושוב<ref></ref> או החלפה למחרוזת בפורמט printf, כאשר המשתנה רחוק מהמקום שבו נעשה בו שימוש. הדגמה של שלוש החלופות:
<syntaxhighlight lang="python">
apples = 4
print("I have ${apples} apples.") # string interpolation
print("I have " + apples + " apples.") # string concatenation
print("I have %s apples.", apples) # format string
</syntaxhighlight>

בדרך כלל מוצעים שני סוגים של ביטוי מילולי: אחד עם אינטרפולציה מופעלת, השני בלי. כאשר אין הפעלה של אינטרפולציה, עדיין יכולה להתבצע פעולת פענוח של מחרוזות מיוחדות, לדוגמה רצף כגון &quot; עשוי להתפענח בהקשרים מסוימים כמרכאות (למשל ב-HTML), אפילו כאשר אין תמיכה באינטרפולציה. מחרוזות ללא אינטרפולציה שגם נמלטות מפענוח רצפים נקראות מחרוזות גולמיות. לדוגמה, בממשק שורת פקודה של יוניקס, מחרוזות במירכאות בודדות הן גולמיות, ואילו מחרוזות במירכאות כפולות מפעילות אינטרפולציה. מצייני מיקום מיוצגים בדרך כלל על ידי סימן ייעודי (בדרך כלל <code>$</code> או <code>%</code>), למשל או , או עם סוגריים מסולסלים, למשל <code>{apples}</code>, ולפעמים שניהם, למשל . במקרים מסוימים ניתן להשתמש במפרטי עיצוב נוספים (כמו ב-printf), למשל <code>{apples:3}</code>, ובמקרים מסוימים ניתן לבצע אינטרפולציה של מפרטי העיצוב עצמם, למשל <code>{apples:width}</code> . הרחבת המחרוזת מתרחשת בדרך כלל בזמן ריצה.

תמיכת השפה באינטרפולציה של מחרוזת משתנה מאוד בין שפות. שפות מסוימות אינן מציעות אינטרפולציה למחרוזות, ומשתמשות במקום זאת בשרשור, פונקציות עיצוב פשוטות או ספריות של תבניות. אינטרפולציה של מחרוזת נפוצה בשפות תכנות רבות העושות שימוש רב בייצוגי מחרוזת של נתונים, כגון Apache Groovy, ג'וליה, Kotlin, Perl, PHP, פייתון, Ruby, סקאלה, סוויפט, Tcl ורוב ממשקי שורת הפקודה של יוניקס.

== אלגוריתמים ==
ישנם שני סוגים עיקריים של אלגוריתמי הרחבת משתנים לאינטרפולציה של משתנים:<ref>[https://code.google.com/p/smallest-template-system/wiki/SimplestAlgorithm "smallest-template-system/Simplest algorithms"], an online tutorial for placeholder-template-systems.</ref>
# "החלף והרחב שומרי מקום": יצירת מחרוזת חדשה על בסיס המחרוזת המקורית, על ידי פעולות מצא-החלף. מצא הפניה למשתנה (שומר מקום), החלף אותו בערך המשתנה שלו. אלגוריתם זה אינו מציע אסטרטגיית מטמון.
# "פצל וצרף מחרוזת": פיצול המחרוזת למערך, ומיזוגו עם מערך הערכים המתאים; לאחר מכן צירוף כל הפריטים על ידי שרשור. ניתן לשמור את המחרוזת המפוצלת במטמון לשימוש חוזר, למשל כאשר הערכים משתנים.

== סוגיות אבטחה ==
אינטרפולציה של מחרוזות, כמו שרשור מחרוזות, עשויה להוביל לבעיות אבטחה. אם נתוני קלט של המשתמש יעברו מילוט או סינון שגוי, המערכת תיחשף להזרקת SQL, הזרקת סקריפט, הזרקת ישות חיצונית של XML (XXE) והתקפות סקריפטים בין-אתרים (XSS).<ref></ref>

דוגמה להזרקת SQL:
 query = " "
אם <code>$id</code> מוחלף ב " <code>'; </code> ", ביצוע שאילתה זו ימחק את כל הנתונים בטבלה.

== דוגמאות ==
=== ABAP ===
<syntaxhighlight lang="abap">
DATA(apples) = 4.
WRITE |I have { apples } apples|.
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">
I have 4 apples
</syntaxhighlight>

=== באש ===
<syntaxhighlight lang="bash">
apples=4
echo "I have $apples apples"
# or
echo "I have ${apples} apples"
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">I have 4 apples</syntaxhighlight>

=== BOO ===
<syntaxhighlight lang="boo">
apples = 4
print("I have $(apples) apples")
# or
print("I have {0} apples" % apples)
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">I have 4 apples</syntaxhighlight>

=== סי שארפ ===
החל מגרסה 6 קיימת תמיכה באינטרפולציה של מחרוזת.
<syntaxhighlight lang="csharp">
var apples = 4;
var bananas = 3;

Console.WriteLine($"I have {apples} apples");
Console.WriteLine($"I have {apples + bananas} fruits");
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">
I have 4 apples
I have 7 fruits
</syntaxhighlight>

=== שפת סימון ColdFusion ===
תחביר הסקריפט של ColdFusion Markup Language (CFML):
<syntaxhighlight lang="cfc">
apples = 4;
writeOutput("I have #apples# apples");</syntaxhighlight>תחביר תגיות:<syntaxhighlight lang="cfm">
<cfset apples = 4>
<cfoutput>I have #apples# apples</cfoutput></syntaxhighlight>
הפלט יהיה:
 I have 4 apples

=== CoffeeScript ===
<syntaxhighlight lang="coffeescript">
apples = 4
console.log "I have #{apples} apples"
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">I have 4 apples</syntaxhighlight>

=== Dart ===
<syntaxhighlight lang="ecmascript">
int apples = 4, bananas = 3;
print('I have $apples apples.');
print('I have ${apples+bananas} fruit.');
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">I have 4 apples.
I have 7 fruit.</syntaxhighlight>

=== Go (שפת תכנות) ===
נכון לשנת 2022, בשפת Go אין תמיכה באינטרפולציה של מחרוזות. היו כמה הצעות להוספת תמיכה בגרסה הבאה של השפה, Go 2. במקום אינטרפולציה, גו משתמשת בפורמט printf בפונקציה <code>fmt.Sprintf, בשרשור מחרוזות או בספריות לבניית תבניות כמו text/template.</code>

=== Groovy ===
בשפת גרובי, מחרוזות עם אינטרפולציה ידועות כ-GSStrings:<ref></ref><syntaxhighlight lang="groovy">
def quality = "superhero"
final age = 52
def sentence = "A developer is a $quality, if he is ${age <= 42 ? "young" : "seasoned"}"
println sentence
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">A developer is a superhero if he is seasoned</syntaxhighlight>

=== Haxe ===
<syntaxhighlight lang="haxe">
var apples = 4;
var bananas = 3;
trace('I have $apples apples.');
trace('I have ${apples+bananas} fruit.');
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">I have 4 apples.
I have 7 fruit.</syntaxhighlight>

=== ג'אווה ===
נכון ל-2022, שפת התכנות ג'אווה אינה תומכת באינטרפולציה של מחרוזות, במקום זאת היא משתמשת בפונקציות ליצירת פורמט, הידועות שבהן הן המחלקה <code>MessageFormat (החל מגרסת Java 1.1) והפונקציה הסטטית String.format (החל מגרסה 5 של השפה).</code>

=== JavaScript ===
JavaScript, החל מתקן ECMAScript 2015 (ES6), תומכת באינטרפולציה של מחרוזות תוך שימוש בסימן הטעמה משני (<code>`)</code>. תכונה זו נקראת תבניות מילוליות.<ref></ref> להלן דוגמה:
<syntaxhighlight lang="ecmascript">
const apples = 4;
const bananas = 3;
console.log(`I have ${apples} apples`);
console.log(`I have ${apples + bananas} fruit`);
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">
I have 4 apples
I have 7 fruit
</syntaxhighlight>
ניתן להשתמש בתבנית מילולית גם עבור מחרוזת מרובת שורות:
<syntaxhighlight lang="ecmascript">
console.log(`This is the first line of text.
This is the second line of text.`);
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">
This is the first line of text.
This is the second line of text.
</syntaxhighlight>

=== ג'וליה ===
<syntaxhighlight lang="julia">
apples = 4
bananas = 3
print("I have $apples apples and $bananas bananas, making $(apples + bananas) pieces of fruit in total.")
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">
I have 4 apples and 3 bananas, making 7 pieces of fruit in total.
</syntaxhighlight>

=== Kotlin ===
<syntaxhighlight lang="kotlin">
val quality = "superhero"
val apples = 4
val bananas = 3
val sentence = "A developer is a $quality. I have ${apples + bananas} fruit"
println(sentence)
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">A developer is a superhero. I have 7 fruit</syntaxhighlight>

=== Nemerle ===
<syntaxhighlight lang="boo">
def apples = 4;
def bananas = 3;
Console.WriteLine($"I have $apples apples.");
Console.WriteLine($"I have $(apples + bananas) fruit.");</syntaxhighlight>
השפה תומכת גם בתכונות פורמט מתקדמות, כגון:
<syntaxhighlight lang="boo">def fruit = ["apple", "banana"];
Console.WriteLine($<#I have ..$(fruit; "\n"; f => f + "s")#>);</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">apples
bananas</syntaxhighlight>

=== Nim ===
נים מספקת אינטרפולציה של מחרוזות באמצעות מודול ה-strutils. מחרוזות מילוליות עם פורמט, בהשראת F-string של שפת התכנות פייתון, מסופקות באמצעות מודול strformat, המאקרו strformat מוודא שמחרוזת הפורמט מעוצבת היטב ובעלת טיפוסים נכונים, ולאחר מכן מורחבת לקוד מקור של Nim בזמן ההידור.
<syntaxhighlight lang="nim">
import strutils, strformat
var apples = 4
var bananas = 3
echo "I have $1 apples".format(apples)
echo fmt"I have {apples} apples"
echo fmt"I have {apples + bananas} fruits"

# Multi-line
echo fmt"""
I have
{apples} apples"""

# Debug the formatting
echo fmt"I have {apples=} apples"

# Custom openChar and closeChar characters
echo fmt("I have (apples) {apples}", '(', ')')

# Backslash inside the formatted string literal
echo fmt"""{ "yep\nope" }"""
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">
I have 4 apples
I have 4 apples
I have 7 fruits
I have
4 apples
I have apples=4 apples
I have 4 {apples}
yep
ope
</syntaxhighlight>

=== Nix ===
<syntaxhighlight lang="nix">
let numberOfApples = "4";
in "I have ${numberOfApples} apples"
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">
I have 4 apples
</syntaxhighlight>

=== ParaSail ===
<syntaxhighlight lang="parasail">
const Apples := 4
const Bananas := 3
Println ("I have `(Apples) apples.\n")
Println ("I have `(Apples+Bananas) fruit.\n")
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">
I have 4 apples.
I have 7 fruit.</syntaxhighlight>

=== Perl ===
<syntaxhighlight lang="perl">
my $apples = 4;
my $bananas = 3;
print "I have $apples apples.\n";
print "I have @{[$apples+$bananas]} fruit.\n"; # Uses the Perl array (@) interpolation.
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">
I have 4 apples.
I have 7 fruit.</syntaxhighlight>

=== PHP ===
<syntaxhighlight lang="php">
<?php
$apples = 5;
$bananas = 3;
echo "There are $apples apples and $bananas bananas.";
echo "\n";
echo "I have {$apples} apples and {$bananas} bananas.";
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">There are 5 apples and 3 bananas.
I have 5 apples and 3 bananas.</syntaxhighlight>

כאשר עושים שימוש במירכאות בודדות, לא מבוצעת אינטרפולציה.

=== פייתון ===
Python תומכת באינטרפולציה של מחרוזות החל מגרסה 3.6, תחת השם "formatted string literals".<ref></ref><ref></ref><ref></ref> מחרוזת שכזו מתחילה ב-<code>f</code> או <code>F</code> לפני פתיחת המירכאות, ומשתמשת בסוגריים מסולסלים עבור שומרי המקום:<syntaxhighlight lang="python">
apples = 4
bananas = 3
print(f'I have {apples} apples and {bananas} bananas')
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">
I have 4 apples and 3 bananas</syntaxhighlight>

=== Ruby ===
<syntaxhighlight lang="ruby">
apples = 4
puts "I have #{apples} apples"
# or
puts "I have %s apples" % apples
# or
puts "I have %{a} apples" % {a: apples}
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">I have 4 apples</syntaxhighlight>

=== ראסט ===
לראסט אין אינטרפולציה של מחרוזות באופן כללי, אך השפה מספקת פונקציונליות דומה באמצעות פקודת מאקרו, המכונה "מזהים לכודים במחרוזות פורמט", שהוצגה בגרסה 1.58.0, שפורסמה בינואר 2022.<ref></ref>

ראסט מספקת עיצוב באמצעות מודול [https://doc.rust-lang.org/stable/std/fmt/ std::fmt], אשר מתממשקים אליו באמצעות פקודות מאקרו שונות כגון format!, write!, ו-print!. פקודות מאקרו אלו מומרות לקוד מקור ראסט בזמן ההידור, שם כל ארגומנט מקיים אינטראקציה עם הפורמטר. הפורמטר תומך [https://doc.rust-lang.org/stable/std/fmt/#positional-parameters בפרמטרים מיקומיים], [https://doc.rust-lang.org/stable/std/fmt/#named-parameters פרמטרים] בעלי שם, טיפוסים של ארגומנטים, הגדרת [https://doc.rust-lang.org/stable/std/fmt/#formatting-traits תכונות עיצוב] שונות ולכידת מזהים מהסביבה.<syntaxhighlight lang="rust">
let (apples, bananas) = (4, 3);
// println! captures the identifiers when formatting: the string itself isn't interpolated by Rust.
println!("There are {apples} apples and {bananas} bananas.");
</syntaxhighlight>
הפלט יהיה:
 There are 4 apples and 3 bananas.

=== סקאלה ===
Scala החל מגרסה 2.10 הטמיעה את האינטרפולטורים הבאים של מחרוזות: s, f ו-raw. אפשר גם לכתוב אינטרפולטורים מותאמים אישית או לדרוס את הסטנדרטיים.

האינטרפולטור f הוא מאקרו מהדר המשכתב מחדש מחרוזת פורמט עם ביטויים מוטבעים כקריאה ל-String.format. הוא מוודא שמחרוזת הפורמט מעוצבת היטב ובעלת טיפוסיות נכונה.

==== האינטרפולטורים הסטנדרטיים ====
אינטרפולציית מחרוזת של Scala 2.10+ מאפשרת הטמעת הפניות משתנות ישירות במחרוזות מעובדות. להלן דוגמה:
<syntaxhighlight lang="scala">
val apples = 4
val bananas = 3
//before Scala 2.10
printf("I have %d apples\n", apples)
println("I have %d apples" format apples)
//Scala 2.10+
println(s"I have $apples apples")
println(s"I have ${apples + bananas} fruits")
println(f"I have $apples%d apples")
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">
I have 4 apples</syntaxhighlight>

=== Sciter (tiscript) ===
בשפת Sciter כל פונקציה עם שם שמתחיל ב-$ נחשבת כפונקציה עם אינטרפולציה ולכן האינטרפולציה ניתנת להתאמה אישית ורגישה להקשר:<syntaxhighlight lang="javascript">
var apples = 4
var bananas = 3
var domElement = ...;

domElement.$content(<p>I have {apples} apples</p>);
domElement.$append(<p>I have {apples + bananas} fruits</p>);
</syntaxhighlight>
כאשר:
<syntaxhighlight lang="javascript">domElement.$content(<p>I have {apples} apples</p>);</syntaxhighlight>
הופך לזה:
<syntaxhighlight lang="javascript">domElement.html = "<p>I have " + apples.toHtmlString() + " apples</p>";</syntaxhighlight>

=== Snobol ===
<syntaxhighlight lang="snobol">
 apples = 4 ; bananas = 3
 Output = "I have " apples " apples."
 Output = "I have " (apples + bananas) " fruit."
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">I have 4 apples.
I have 7 fruit.</syntaxhighlight>

=== סוויפט ===

בסוויפט, ניתן ליצור ערך מחרוזת חדש משילוב של קבועים, משתנים, מחרוזות וביטויים על ידי הכללת הערכים שלהם בתוך מחרוזת.<ref></ref> כל פריט המוכנס למחרוזת עטוף בזוג סוגריים, עם קו נטוי אחורי.
<syntaxhighlight lang="fsharp">
let apples = 4
print("I have \(apples) apples")
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">I have 4 apples</syntaxhighlight>

=== Tcl ===
שפת הפקודה של הכלי תמיד תמכה באינטרפולציה של מחרוזות בכל המחרוזות המופרדות במירכאות.
<syntaxhighlight lang="tcl">
set apples 4
puts "I have $apples apples."
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">I have 4 apples.</syntaxhighlight>

אם רוצים לשנות את הפורמט של הערכים ולא רק להחליף אותם, קיימת פונקציית פירמוט.

<syntaxhighlight lang="tcl">
set apples 4
puts [format "I have %d apples." $apples]
</syntaxhighlight>

=== TypeScript ===
נכון לגרסה 1.4, TypeScript תומכת באינטרפולציה של מחרוזות באמצעות סימן הטעמה משני (`). לדוגמה:
<syntaxhighlight lang="ecmascript">
var apples: number = 4;
console.log(`I have ${apples} apples`);
</syntaxhighlight>
הפלט יהיה:
<syntaxhighlight lang="output">I have 4 apples</syntaxhighlight>
The <code>console.log</code> function can be used as a <code>printf</code> function. The above example can be rewritten, thusly:
<syntaxhighlight lang="ecmascript">
var apples: number = 4;
console.log("I have %d apples", apples);
</syntaxhighlight>
הפלט נשאר אותו דבר.

=== Visual Basic ===
נכון ל-Visual Basic 14, אינטרפולציה של מחרוזות נתמכת בשפה.<ref></ref>

<syntaxhighlight lang="ecmascript">
name = "Tom"
Console.WriteLine($"Hello, {name}")
</syntaxhighlight>
ידפיס:
 "Hello, Tom".

== ראו גם ==
* שרשור (מחרוזות)

== הערות שוליים ==

קטגוריה:מחרוזת (מדעי המחשב)