מספרים ומחרוזות#

סקלר יכול להחזיק מספר, מחרוזת או שניהם בבת אחת. Perl ממיר בשקט בין השניים בכל פעם שאופרטור דורש צורה אחת - + רוצה מספרים, . רוצה מחרוזות, לאופרטורי השוואה יש צורות נפרדות מספרית ומחרוזתית. הבנת כללי ההמרה והיכן הם נושכים חיונית לכתיבת Perl צפוי.

ליטרלים מספריים#

ליטרלים של מספרים שלמים מגיעים בחמישה בסיסים:

0                    # zero
12345                # decimal
4_294_967_296        # underscores for legibility (decimal 4.29 billion)
0xff                 # hex      - 255
0Xdead_beef          # hex with underscores
0b01_1011            # binary   - 27
0377                 # octal    - 255 (leading 0, NOT followed by [bBxX])
0o12_345             # octal, alternative spelling (5.33.5+)

ליטרלים של נקודה צפה דורשים נקודה או מעריך:

3.14
0.5                  # leading zero ok
.5                   # leading dot ok
1e3                  # 1000
1.5E-10              # exponent - uppercase or lowercase 'e'

קווים תחתונים מתקבלים בין ספרות בכל מקום - 3.14_15_92, 1_000_000. קווים תחתונים עוקבים מרובים מזהירים: 23__500 מזהיר, 23_500 אינו.

נקודות צפות הקסדצימליות ואוקטליות זקוקות למעריך p (חזקה־של־2):

0x1.999ap-4          # hex float
0b101.01p-1          # binary float
0o7.65p2             # octal float

המעריך p נדרש עבור נקודות צפות לא־עשרוניות. 0x1F.5 רגיל הוא שגיאת פרסור.

מחרוזת → מספר#

כאשר Perl ממיר מחרוזת למספר, הוא צורך את הקידומת הארוכה ביותר הנראית כמספר ומתעלם מהשאר:

"42"        + 0      # 42
"42abc"     + 0      # 42       - leading digits parsed
"abc42"     + 0      # 0        - no leading digits
" \t  42"   + 0      # 42       - leading whitespace ok
"4_2"       + 0      # 4        - underscores in literals only, NOT strings
"0xFF"      + 0      # 0        - hex prefix NOT auto-recognised
"3.14e2"    + 0      # 314      - scientific notation parsed
"Inf"       + 0      # Inf      - case-insensitive infinity
"NaN"       + 0      # NaN

אי־ההתאמה בין ליטרלים מספריים (המכבדים _, 0x, 0b, 0) לבין מחרוזות מספריות (שאינן מכבדות אף אחד מהם) היא כלל ההמרה שמועדים בו ביותר. כדי להמיר מחרוזת בצורה לא־עשרונית, השתמשו ב־hex או ב־oct:

my $bytes = hex "FF";          # 255
my $bytes = hex "0xFF";        # 255  - hex() ignores the 0x
my $perms = oct "0755";        # 493
my $perms = oct "0o755";       # 493  - explicit octal prefix
my $bytes = oct "0xFF";        # 255  - oct() recognises any prefix

תחת use warnings, פעולת חשבון על מחרוזת שאינה מתחילה בקידומת מספר פולטת Argument ”…“ isn’t numeric in addition (+). התוצאה עדיין 0; האזהרה היא האות. כתיבת קוד סובלני המקבל קלט משתמש פירושה לעיתים קרובות סינון תחילה עם Scalar::Util::looks_like_number או עם regex.

מספר → מחרוזת#

Perl ממיר מספר למחרוזת באותה לוגיקה כמו sprintf("%g", $n) עבור נקודות צפות וייצוג עשרוני המובן מאליו עבור מספרים שלמים:

my $i = 42;             "$i"   # "42"
my $f = 3.14;           "$f"   # "3.14"
my $z = 0.0;            "$z"   # "0"        - not "0.0"
my $b = 1e10;           "$b"   # "10000000000"
my $s = 1e20;           "$s"   # "1e+20"    - switches to scientific past ~15 digits
my $n = "Inf" + 0;      "$n"   # "Inf"

הדיוק כברירת מחדל הוא מספיק ספרות כדי לעשות roundtrip לרוב ה־doubles. לשליטה מדויקת, פרמטו במפורש עם sprintf:

sprintf "%.2f", 3.14159           # "3.14"
sprintf "%05d", 42                # "00042"
sprintf "%e", 1234567             # "1.234567e+06"

שרשור מאלץ מחרוזות; חשבון מאלץ מספרים#

"42" + "3"           # 45    - both coerced to numbers
42 . 3               # "423" - both coerced to strings
"3" x "5"            # "33333" - left operand string, right operand number

האופרטור . הוא אופרטור ההמרה־למחרוזת־המפורש; + הוא אופרטור ההמרה־למספר־המפורש. סקלר המחזיק מספר שאתם רוצים כמחרוזת ניתן לשרשור עם "":

my $s = "" . $n;     # idiomatic "stringify"
my $s = "$n";        # same; usually clearer

סקלר המחזיק מחרוזת שאתם רוצים כמספר מוסיף 0:

my $n = $s + 0;      # idiomatic "numify"

השוואה מספרית מול מחרוזתית#

שתי משפחות מקבילות של אופרטורי השוואה עם סמנטיקה שונה:

מספרי

מחרוזת

משמעות

==

eq

שווה

!=

ne

לא שווה

<

lt

קטן

<=

le

קטן או שווה

>

gt

גדול

>=

ge

גדול או שווה

<=>

cmp

השוואה תלת־כיוונית

סדר המיון שונה באופן דרמטי עבור ערכים הנראים כמספרים אך גדולים:

"10" <  "9"          # FALSE - 10 < 9 numerically
"10" lt "9"          # TRUE  - '1' < '9' lexicographically

מיינו מספרים מספרית:

my @sorted = sort { $a <=> $b } @numbers;       # numeric
my @sorted = sort                @strings;       # default - string
my @sorted = sort { $a cmp $b }  @strings;       # explicit string

בחירת האופרטור הלא־נכון היא מקור הבאגים של ”my sort is wrong“. ראו השוואה מספרית ו־השוואה מחרוזתית.

נקודה צפה: דיוק, Inf, NaN#

רוב ה־Perls משתמשים בנקודות צפות בדיוק כפול של IEEE 754 - בערך 15–17 ספרות עשרוניות של דיוק. ההפתעה הקלאסית:

0.1 + 0.2 == 0.3      # FALSE - neither side is exactly representable
                      # 0.1 + 0.2 = 0.30000000000000004

עבור כסף או כל דבר שחייב להיות מדויק, עבדו במספרים שלמים (סנטים במקום דולרים) או השתמשו במודול bignum:

use bignum;            # auto-promotes to arbitrary precision
0.1 + 0.2 == 0.3      # TRUE under bignum

use Math::BigInt;
my $big = Math::BigInt->new("100000000000000000000") + 1;

Inf ו־NaN הם ערכים אמיתיים:

my $inf = 9 ** 9 ** 9;       # Inf - overflow
my $nan = $inf - $inf;       # NaN - undefined arithmetic
my $nan = "NaN" + 0;         # NaN - accepted from string

$nan == $nan                  # FALSE - NaN never equals anything
$nan != $nan                  # TRUE  - including itself

Inf ו־NaN הם ללא רגישות לאותיות גדולות וקטנות בקלט ויש להם מספר כתיבים (Infinity, 1.#INF, …); בפלט Perl מנרמל לצורות הקצרות.

שימו לב ש־perl5 מייצר שגיאות קטלניות עבור 1/0 ו־sqrt(-1); אלה אינם מייצרים NaN. הם חריגים, לא חשבוניים.

פרסור מספרים מושפע־locale#

תחת use locale בתוספת locale פעיל של POSIX, הנקודה העשרונית היא מה שה־locale אומר. זה משפיע על פרסור והמרה למחרוזת של נקודות צפות:

use locale;
use POSIX qw(setlocale LC_NUMERIC);
setlocale LC_NUMERIC, 'de_DE.UTF-8';   # German uses ',' as decimal

my $x = 3.14;
print "$x\n";                            # "3,14"  - locale formatting
"3,14" + 0                                # 3.14    - locale parsing

זה לעיתים רחוקות מה שאתם רוצים עבור החלפת נתונים. רוב הקוד הקורא או כותב נתונים מובנים צריך במפורש לא להיות בתחום ה־use locale, כך ש־. תהיה תמיד הנקודה העשרונית. השתמשו בפרמוט locale רק בגבול שבו הפלט מיועד לקורא אנושי.

”Looks like a number“#

הכללים לשאלה אם מחרוזת היא ”numeric enough“ אינם פשוטים לשילוב בשורה; השתמשו ב־Scalar::Util::looks_like_number:

use Scalar::Util qw(looks_like_number);

looks_like_number("42")        # true
looks_like_number("3.14e10")   # true
looks_like_number("Inf")       # true
looks_like_number("NaN")       # true
looks_like_number("0xFF")      # FALSE - hex strings are not "numeric"
looks_like_number("")          # FALSE - empty string
looks_like_number(undef)       # FALSE
looks_like_number("3.14abc")   # FALSE - trailing junk

זוהי פונקציית האימות - קפדנית, ללא זבל מוביל, ללא זבל גורר, ללא קידומות hex/oct. היא תואמת לתנאים שבהם Perl ישתמש בצורה המספרית השמורה במטמון של מספר במקום לפרסר מחדש בכל פעולת חשבון.

ראו גם#