این دستور perlfaq4 است که می تواند در ارائه دهنده هاست رایگان OnWorks با استفاده از یکی از چندین ایستگاه کاری آنلاین رایگان ما مانند Ubuntu Online، Fedora Online، شبیه ساز آنلاین ویندوز یا شبیه ساز آنلاین MAC OS اجرا شود.
برنامه:
نام
perlfaq4 - دستکاری داده ها
نسخه
5.021009 نسخه
شرح
این بخش از سوالات متداول به سوالات مربوط به دستکاری اعداد، تاریخ ها، رشته ها،
آرایه ها، هش ها و مشکلات داده های متفرقه.
داده ها: تعداد
چرا am I گرفتن طولانی اعداد اعشاری (به عنوان مثال، 19.9499999999999) در عوض of la تعداد I باید be
گرفتن (به عنوان مثال، 19.95)
برای توضیح طولانی، به کتاب "آنچه که هر دانشمند کامپیوتر باید بداند" اثر دیوید گلدبرگ مراجعه کنید
درباره حساب ممیز شناور
(<http://web.cse.msu.edu/~cse320/Documents/FloatingPoint.pdf>)
در داخل، رایانه شما اعداد ممیز شناور را به صورت باینری نشان می دهد. دیجیتال (مانند
قدرت دو) کامپیوترها نمی توانند تمام اعداد را دقیقاً ذخیره کنند. برخی از اعداد واقعی از دست می دهند
دقت در فرآیند این یک مشکل در نحوه ذخیره اعداد و تأثیرات رایانهها است
همه زبان های کامپیوتر، نه فقط پرل.
perlnumber جزئیات بد نمایش و تبدیل اعداد را نشان می دهد.
برای محدود کردن تعداد ارقام اعشار در اعداد خود، می توانید از "printf" یا استفاده کنید
تابع "sprintf". برای جزئیات بیشتر به "حساب ممیز شناور" در perlop مراجعه کنید.
printf "%.2f"، 10/3;
my $number = sprintf "%.2f", 10/3;
چرا is int() شکسته شده؟
"int()" شما به احتمال زیاد به خوبی کار می کند. این اعداد و ارقام هستند که کاملاً اینطور نیستند
تو فکر می کنی.
ابتدا به پاسخ «چرا به جای
اعدادی که باید دریافت کنم (مثلاً 19.95)؟"
به عنوان مثال ، این
print int(0.6/0.2-2)، "\n";
در اکثر رایانه ها 0 چاپ می شود نه 1، زیرا حتی اعداد ساده ای مانند 0.6 و 0.2
نمی توان دقیقاً با اعداد ممیز شناور ارائه کرد. آنچه در بالا فکر می کنید به عنوان
"سه" واقعا بیشتر شبیه 2.9999999999999995559 است.
چرا نه my اکتال داده ها تفسیر شده به درستی؟
(با مشارکت برایان دی فوی)
احتمالاً میخواهید یک رشته را به یک عدد تبدیل کنید، که پرل فقط آن را به صورت a تبدیل میکند
عدد اعشاری. هنگامی که پرل یک رشته را به عدد تبدیل می کند، فاصله های اصلی و
صفر می شود، سپس فرض می کنیم بقیه ارقام در پایه 10 هستند:
my $string = '0644';
چاپ $string + 0; # چاپ 644
چاپ $string + 44; # چاپ 688، مطمئناً هشتی نیست!
این مشکل معمولاً شامل یکی از داخلی های Perl است که همان نام Unix را دارد
دستوری که از اعداد اکتالی به عنوان آرگومان در خط فرمان استفاده می کند. در این مثال، "chmod"
در خط فرمان میداند که اولین آرگومان آن هشتگانه است، زیرا این کار را انجام میدهد:
%prompt> فایل chmod 644
اگر می خواهید از همان ارقام تحت اللفظی (644) در پرل استفاده کنید، باید به پرل بگویید که درمان کند.
آنها را به عنوان اعداد اکتالی یا با پیشوند ارقام با 0 یا با استفاده از "oct":
chmod( 0644, $filename ); # راست، دارای صفر اول است
chmod( اکتبر(644), $filename ); # نیز درست است
مشکل زمانی پیش میآید که شما اعداد خود را از چیزی که پرل فکر میکند a است، بگیرید
رشته، مانند آرگومان خط فرمان در @ARGV:
chmod($ARGV[0], $filename ); # اشتباه است، حتی اگر "0644"
chmod( oct($ARGV[0]), $filename ); # صحیح، رشته را به عنوان هشتی در نظر بگیرید
برای اطمینان از آن، همیشه میتوانید مقداری را که استفاده میکنید، با چاپ آن در نماد هشتگانه بررسی کنید
مطابق با آنچه شما فکر می کنید باید باشد. آن را در قالب هشت و اعشار چاپ کنید:
printf "0%o %d", $number, $number;
میکند پرل داشته باشد a گرد() عملکرد؟ چی در باره ceil() و کف()? ماشه کارکرد؟
به یاد داشته باشید که "int()" فقط به سمت 0 کوتاه می شود. برای گرد کردن به تعداد معینی از
رقم، "sprintf()" یا "printf()" معمولا ساده ترین مسیر است.
printf("%.3f"، 3.1415926535); # چاپ 3.142
ماژول POSIX (بخشی از توزیع استاندارد پرل) "ceil()"، "floor()"، را پیاده سازی می کند.
و تعدادی دیگر از توابع ریاضی و مثلثاتی.
از POSIX استفاده کنید.
my $ceil = ceil(3.5); # 4
my $floor = floor(3.5); # 3
در 5.000 تا 5.003 پرل، مثلثات در ماژول Math::Complex انجام شد. با 5.004،
ماژول Math::Trig (بخشی از توزیع استاندارد پرل)
توابع مثلثاتی در داخل از ماژول Math::Complex و برخی توابع استفاده می کند
می تواند از محور واقعی به صفحه مختلط، به عنوان مثال سینوس معکوس از
2.
گرد کردن در برنامه های مالی می تواند پیامدهای جدی داشته باشد و روش گرد کردن
مورد استفاده باید دقیقا مشخص شود. در این موارد، احتمالاً اعتماد نکردن به درد می خورد
هر سیستم گرد کردن توسط Perl استفاده می شود، اما در عوض برای اجرای گرد کردن
عملکردی که خودتان نیاز دارید
برای اینکه بفهمید چرا، توجه کنید که چگونه همچنان در تناوب نیمه راه با مشکل مواجه خواهید شد:
برای ($i من = 0؛ $i < 1.01؛ $i += 0.05) { printf "%.1f ",$i}
0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7
0.8 0.8 0.9 0.9 1.0 1.0
پرل را سرزنش نکنید. این همان چیزی است که در C. IEEE می گوید ما باید این کار را انجام دهیم. اعداد پرل که
مقادیر مطلق اعداد صحیح زیر 2**31 هستند (در ماشین های 32 بیتی) تقریباً مانند
اعداد صحیح ریاضی شماره های دیگر تضمین نمی شوند.
چگونه do I تبدیل میان عددی بازنمایی ها/پایه ها/ریشه ها؟
مثل همیشه پرل بیش از یک راه برای انجام آن وجود دارد. در زیر چند نمونه از
رویکردهایی برای ایجاد تبدیل های مشترک بین نمایش های اعداد. این در نظر گرفته شده است
به جای اینکه جامع باشد، نماینده باشد.
برخی از نمونه های بعدی در perlfaq4 از ماژول Bit::Vector از CPAN استفاده می کنند. دلیل
شما می توانید Bit::Vector را به جای توابع داخلی perl انتخاب کنید که با آن کار می کند
اعداد با هر اندازه، که برای سرعت در برخی از عملیات، و حداقل برای بهینه سازی شده است
برخی از برنامه نویسان ممکن است با نماد آشنا باشند.
چگونه هگزادسیمال را به اعشار تبدیل کنم؟
با استفاده از پرل ساخته شده در تبدیل نماد "0x":
من $dec = 0xDEADBEEF;
با استفاده از تابع "هگز":
my $dec = hex("DEADBEEF");
استفاده از "pack":
my $dec = unpack("N", pack("H8", substr("0" x 8 . "DEADBEEF", -8)));
با استفاده از ماژول CPAN "Bit::Vector":
استفاده از بیت::بردار;
my $vec = Bit::Vector->new_Hex(32، "DEADBEEF");
my $dec = $vec->to_Dec();
چگونه از اعشار به هگزادسیمال تبدیل کنم؟
با استفاده از "sprintf":
my $hex = sprintf("%X", 3735928559); # فوکوس خودکار حروف بزرگ
my $hex = sprintf("%x", 3735928559); # حروف کوچک af
با استفاده از "باز کردن بسته":
my $hex = unpack("H*", pack("N", 3735928559));
استفاده از بیت::بردار:
استفاده از بیت::بردار;
my $vec = Bit::Vector->new_Dec(32, -559038737);
my $hex = $vec->to_Hex();
و Bit::Vector از تعداد بیت های فرد پشتیبانی می کند:
استفاده از بیت::بردار;
my $vec = Bit::Vector->new_Dec(33, 3735928559);
$vec->تغییر اندازه(32)؛ # در صورت ناخواسته، 0 پیشرو را سرکوب کنید
my $hex = $vec->to_Hex();
چگونه از هشتی به اعشاری تبدیل کنم؟
استفاده از ساخت پرل در تبدیل اعداد با صفرهای اول:
من $dec = 033653337357; # به 0 پیشرو توجه کنید!
با استفاده از تابع "oct":
my $dec = oct("33653337357");
استفاده از بیت::بردار:
استفاده از بیت::بردار;
my $vec = Bit::Vector->جدید(32)؛
$vec->Chunk_List_Store(3، split(//، معکوس "33653337357"));
my $dec = $vec->to_Dec();
چگونه از اعشار به هشتی تبدیل کنم؟
با استفاده از "sprintf":
my $oct = sprintf("%o", 3735928559);
استفاده از بیت::بردار:
استفاده از بیت::بردار;
my $vec = Bit::Vector->new_Dec(32, -559038737);
my $oct = reverse join('', $vec->Chank_List_Read(3))؛
چگونه از باینری به اعشاری تبدیل کنم؟
Perl 5.6 به شما امکان می دهد اعداد باینری را مستقیماً با نماد "0b" بنویسید:
شماره $ من = 0b10110110;
با استفاده از "oct":
my $input = "10110110";
my $decimal = oct( "0b$input" );
استفاده از "pack" و "ord":
my $decimal = ord(pack('B8', '10110110'));
استفاده از "pack" و "unpack" برای رشته های بزرگتر:
my $int = unpack("N", pack("B32",
substr("0" x 32. "11110101011011011111011101111"، -32)));
my $dec = sprintf("%d", $int);
# substr () برای قرار دادن یک رشته 32 کاراکتری با صفر به سمت چپ استفاده می شود.
استفاده از بیت::بردار:
my $vec = Bit::Vector->new_Bin(32, "11011110101011011011111011101111");
my $dec = $vec->to_Dec();
چگونه از اعشار به باینری تبدیل کنم؟
با استفاده از "sprintf" (perl 5.6+):
my $bin = sprintf("%b", 3735928559);
با استفاده از "باز کردن بسته":
my $bin = unpack("B*", pack("N", 3735928559));
استفاده از بیت::بردار:
استفاده از بیت::بردار;
my $vec = Bit::Vector->new_Dec(32, -559038737);
my $bin = $vec->to_Bin();
تبدیلهای باقیمانده (مانند hex -> oct، bin -> hex، و غیره) به عنوان یک
تمرین برای خواننده متمایل
چرا نمی کند & کار la راه I می خواهم it به؟
رفتار عملگرهای حسابی باینری بستگی به این دارد که آیا آنها روی اعداد استفاده می شوند یا نه
رشته های. عملگرها یک رشته را به عنوان یک سری بیت در نظر می گیرند و با آن (رشته
"3" الگوی بیت 00110011 است). عملگرها با شکل باینری یک عدد (the
شماره 3 به عنوان الگوی بیت 00000011 در نظر گرفته می شود.
بنابراین، گفتن "11 و 3" عمل "و" را روی اعداد انجام می دهد (بازده 3). گفتن "11" و
"3" عمل "و" را روی رشته ها انجام می دهد (بازده "1").
بیشترین مشکلات با "&" و "|" به این دلیل بوجود می آیند که برنامه نویس فکر می کند آنها یک عدد اما دارند
واقعاً یک رشته است یا برعکس. برای جلوگیری از این امر، استدلال ها را به صراحت مشخص کنید
(با استفاده از "" یا "qq()") یا آنها را به صراحت به اعداد تبدیل کنید (با استفاده از "0+$arg"). بقیه
به این دلیل است که برنامه نویس می گوید:
if ("\020\020" & "\101\101") {
#...
}
اما رشته ای متشکل از دو بایت تهی (نتیجه "\020\020" و "\101\101") یک
مقدار نادرست در پرل تو نیاز داری:
if (("\020\020" & "\101\101") !~ /[^\000]/) {
#...
}
چگونه do I تکثیر ماتریس ها؟
از ماژول های Math::Matrix یا Math::MatrixReal (موجود در CPAN) یا PDL استفاده کنید
پسوند (همچنین از CPAN موجود است).
چگونه do I انجام دادن an عمل on a سلسله of اعداد صحیح؟
برای فراخوانی یک تابع در هر عنصر در یک آرایه و جمع آوری نتایج، از موارد زیر استفاده کنید:
my @results = map { my_func($_) } @array;
مثلا:
من @triple = map { 3 * $_ } @single;
برای فراخوانی یک تابع در هر عنصر از یک آرایه، اما نادیده گرفتن نتایج:
foreach my $iterator (@array) {
some_func($iterator);
}
برای فراخوانی یک تابع در هر عدد صحیح در یک محدوده (کوچک)، شما می توان استفاده کنید:
my @results = map { some_func($_) } (5 .. 25);
اما باید توجه داشته باشید که در این فرم، عملگر ".." لیستی از همه را ایجاد می کند
اعداد صحیح در محدوده، که می تواند حافظه زیادی را برای محدوده های بزرگ بگیرد. با این حال
هنگام استفاده از ".." در حلقه "for" مشکلی ایجاد نمی شود، زیرا در این صورت محدوده
اپراتور بهینه شده است تکرار در محدوده، بدون ایجاد کل لیست. بنابراین
نتایج @ من = ();
برای $i من (5 .. 500_005) {
push(@نتایج، some_func($i));
}
و یا حتی
push(@results, some_func($_)) برای 5 .. 500_005;
یک لیست متوسط از 500,000 عدد صحیح ایجاد نمی کند.
چگونه می توان I تولید رومی اعداد؟
دریافت کنیدhttp://www.cpan.org/modules/by-module/Roman> ماژول.
چرا نیستند my تصادفی تعداد تصادفی؟
اگر از نسخهای از Perl قبل از 5.004 استفاده میکنید، باید یک بار در ابتدای این نسخه با "srand" تماس بگیرید.
برنامه شما برای بذر مولد اعداد تصادفی.
BEGIN {srand() if $] < 5.004 }
5.004 و بعد از آن به طور خودکار در ابتدا "srand" را صدا می زنند. «سرند» را بیشتر از آن صدا نکنید
یک بار - اعداد خود را کمتر تصادفی می کنید، نه بیشتر.
رایانه ها در قابل پیش بینی بودن خوب هستند و در تصادفی بودن بد هستند (علیرغم ظاهر
ناشی از اشکالات در برنامه های شما :-). در تصادفی مقاله در "بیشتر از شما
خواستم بدانم» مجموعه درhttp://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz>، با حسن نیت از
تام فینیکس، بیشتر در این مورد صحبت می کند. جان فون نویمان میگوید: «هر کسی که تلاش میکند
تولید اعداد تصادفی با ابزارهای قطعی، البته زندگی در حالت گناه است."
پرل برای اجرای "rand" و "srand" به سیستم اساسی متکی است. در برخی از
سیستم ها، اعداد تولید شده به اندازه کافی تصادفی نیستند (به خصوص در ویندوز: ببینید
<http://www.perlmonks.org/?node_id=803632>). چندین ماژول CPAN در فضای نام "ریاضی".
پیاده سازی مولدهای شبه تصادفی بهتر؛ به عنوان مثال ریاضی::تصادفی::MT ("Mersenne
Twister، سریع)، یا Math::TrulyRandom (از عیوب تایمر سیستم استفاده می کند تا
تولید اعداد تصادفی، که نسبتا کند است). الگوریتم های بیشتری برای اعداد تصادفی هستند
شرح داده شده در "دستورالعمل های عددی در C" درhttp://www.nr.com/>
چگونه do I دریافت کنید a تصادفی عدد میان X و Y?
برای به دست آوردن یک عدد تصادفی بین دو مقدار، می توانید از "rand()" داخلی برای بدست آوردن a استفاده کنید
عدد تصادفی بین 0 و 1. از آنجا، آن را به محدوده ای که می خواهید منتقل می کنید.
"rand($x)" عددی را برمی گرداند که "0 <= rand($x) <$x". بنابراین آنچه می خواهید داشته باشید
perl figure out یک عدد تصادفی در محدوده 0 تا تفاوت بین شماست X
و Y.
یعنی برای بدست آوردن عددی بین 10 تا 15 با احتساب عدد تصادفی بین 0 می خواهید.
و 5 که سپس می توانید به 10 اضافه کنید.
my $number = 10 + int rand( 15-10+1 ); # ( 10,11,12,13,14،15،XNUMX،XNUMX،XNUMX، یا XNUMX)
از این رو تابع ساده زیر را برای انتزاع آن استخراج می کنید. تصادفی را انتخاب می کند
عدد صحیح بین دو عدد صحیح داده شده (شامل). مثلا:
"random_int_between(50,120)".
sub random_int_between {
my($min، $max) = @_;
# فرض کنید که این دو آرگومان خود اعداد صحیح هستند!
اگر $min == $max;
($min، $max) = ($max، $min) اگر $min > $max;
بازگشت $min + int rand(1 + $max - $min);
}
داده ها: تاریخ
چگونه do I پیدا کردن la روز or هفته of la سال؟
روز سال در لیستی است که توسط تابع "زمان محلی" برگردانده شده است. بدون یک
آرگومان "localtime" از زمان جاری استفاده می کند.
my $day_of_year = (زمان محلی)[7];
ماژول POSIX همچنین می تواند تاریخ را به عنوان روز سال یا هفته سال فرمت کند.
از POSIX qw/strftime/ استفاده کنید.
my $day_of_year = strftime "%j"، localtime;
my $week_of_year = strftime "%W"، localtime;
برای دریافت روز سال برای هر تاریخی، از "mktime" POSIX استفاده کنید تا زمان را در ثانیه های دوره ای بدست آورید.
برای استدلال به "زمان محلی".
از POSIX qw/mktime strftime/ استفاده کنید.
my $week_of_year = strftime "%W"،
localtime( mktime( 0, 0, 0, 18, 11, 87 ));
شما همچنین می توانید از Time::Piece استفاده کنید که با Perl ارائه می شود و یک "زمان محلی" ارائه می دهد
یک شی را برمی گرداند:
استفاده از Time::Piece;
my $day_of_year = localtime->yday;
my $week_of_year = localtime->week;
ماژول Date::Calc دو تابع را برای محاسبه اینها نیز ارائه می دهد:
استفاده از تاریخ::Calc;
my $day_of_year = Day_of_Year( 1987, 12, 18 );
my $week_of_year = Week_of_Year( 1987, 12, 18 );
چگونه do I پیدا کردن la جاری قرن or هزاره؟
از توابع ساده زیر استفاده کنید:
زیر get_century {
return int((((زمان محلی(شیفت || زمان))[5] + 1999))/100);
}
زیر get_millennium {
بازگشت 1+int((((زمان محلی(shift || زمان))[5] + 1899))/1000);
}
در برخی از سیستم ها، تابع "strftime()" ماژول POSIX به صورت غیر توسعه یافته است.
روش استاندارد برای استفاده از فرمت %C، که آنها گاهی اوقات ادعا می کنند "قرن" است. این نیست،
زیرا در اکثر چنین سیستم هایی، این تنها دو رقم اول سال چهار رقمی است،
و بنابراین نمی توان از آن برای تعیین قابل اعتماد قرن یا هزاره فعلی استفاده کرد.
چگونه می توان I مقايسه كردن دو تاریخ و پیدا کردن la تفاوت؟
(با مشارکت برایان دی فوی)
شما فقط می توانید تمام تاریخ های خود را به عنوان یک عدد ذخیره کنید و سپس کم کنید. زندگی همیشه اینطور نیست
هر چند ساده
ماژول Time::Piece که با Perl ارائه می شود، نسخه محلی را جایگزین می کند
یک شی را برمی گرداند. همچنین اپراتورهای مقایسه را بیش از حد بارگذاری می کند تا بتوانید آنها را مقایسه کنید
به طور مستقیم:
استفاده از Time::Piece;
my $date1 = localtime( $some_time );
my $date2 = localtime( $some_other_time );
if( $date1 < $date2 ) {
چاپ "تاریخ در گذشته بود\n"؛
}
شما همچنین می توانید تفاوت ها را با تفریق دریافت کنید، که یک شی Time::Seconds را برمی گرداند:
my $diff = $date1 - $date2;
چاپ "تفاوت این است ", $date_diff->days, " days\n";
اگر می خواهید با تاریخ های فرمت شده کار کنید، ماژول های Date::Manip، Date::Calc یا DateTime
می تواند به شما کمک کند.
چگونه می توان I گرفتن a رشته و دور زدن it به دوره ثانیه؟
اگر به اندازه کافی یک رشته معمولی است که همیشه قالب یکسانی داشته باشد، می توانید آن را تقسیم کنید
و قطعات را در ماژول استاندارد Time::Local به "timelocal" منتقل کنید. در غیر این صورت، شما
باید به ماژول های Date::Calc، Date::Parse و Date::Manip از CPAN نگاه کنید.
چگونه می توان I پیدا کردن la جولیان روز؟
(با مشارکت برایان دی فوی و دیو کراس)
میتوانید از ماژول Time::Piece، بخشی از کتابخانه استاندارد، استفاده کنید که میتواند a را تبدیل کند
تاریخ/زمان تا یک روز جولیان:
$ perl -MTime::Piece -le 'print localtime->julian_day'
2455607.7959375
یا روز جولیان اصلاح شده:
$ perl -MTime::Piece -le 'print localtime->mjd'
55607.2961226851
یا حتی روز سال (که برخی از مردم آن را روز جولیانی می دانند):
$ perl -MTime::Piece -le 'print localtime->yday'
45
همچنین می توانید همین کارها را با ماژول DateTime انجام دهید:
$ perl -MDateTime -le'print DateTime->today->jd'
2453401.5
$ perl -MDateTime -le'print DateTime->today->mjd'
53401
$ perl -MDateTime -le'print DateTime->today->doy'
31
می توانید از ماژول Time::JulianDay موجود در CPAN استفاده کنید. مطمئن شوید که واقعاً می خواهید
با این حال، یک روز جولیانی را پیدا کنید، زیرا بسیاری از مردم نظرات متفاوتی در مورد روزهای جولیان دارند (نگاه کنید به
<http://www.hermetic.ch/cal_stud/jdn.htm> به عنوان مثال):
$ perl -MTime::JulianDay -le 'print local_julian_day(time)'
55608
چگونه do I پیدا کردن دیروز تاریخ؟
(با مشارکت برایان دی فوی)
برای انجام صحیح این کار، می توانید از یکی از ماژول های "تاریخ" استفاده کنید زیرا با تقویم ها کار می کنند
به جای زمان ماژول DateTime آن را ساده می کند و ساعت یکسانی از روز را به شما می دهد،
فقط یک روز قبل، با وجود تغییر ساعت تابستانی:
از DateTime استفاده کنید.
my $yesterday = DateTime->now->subtract( days => 1 );
چاپ "دیروز $دیروز بود\n";
همچنین می توانید از ماژول Date::Calc با استفاده از تابع "Today_and_Now" استفاده کنید.
استفاده از تاریخ::Calc qw( Today_and_Now Add_Delta_DHMS );
my @date_time = Add_Delta_DHMS( Today_and_Now(), -1, 0, 0, 0 );
چاپ "@date_time\n"؛
بیشتر مردم سعی می کنند از زمان به جای تقویم برای تعیین تاریخ استفاده کنند، اما این
فرض می کند که هر روز بیست و چهار ساعت است. برای اکثر مردم، دو روز در سال وجود دارد
هنگامی که آنها نیستند: سوئیچ به و از زمان تابستان این را خاموش می کند. به عنوان مثال
بقیه پیشنهادات گاهی اشتباه خواهند بود:
شروع با Perl 5.10، Time::Piece و Time::Seconds بخشی از استاندارد هستند.
توزیع، بنابراین ممکن است فکر کنید که می توانید کاری شبیه به این انجام دهید:
استفاده از Time::Piece;
استفاده از زمان::ثانیه;
my $yesterday = localtime() - ONE_DAY; # اشتباه
چاپ "دیروز $دیروز بود\n";
ماژول Time::Piece یک "زمان محلی" جدید را صادر می کند که یک شی را برمی گرداند و Time::seconds
ثابت "ONE_DAY" را صادر می کند که تعداد ثانیه تنظیم شده است. این بدان معنی است که همیشه
زمان را 24 ساعت قبل می دهد که همیشه دیروز نیست. این می تواند مشکلاتی را در اطراف ایجاد کند
پایان زمان تابستانی زمانی که یک روز 25 ساعته باشد.
شما هم همین مشکل را با Time::Local دارید که برای آن ها جواب اشتباه می دهد
همان موارد خاص:
# ارائه شده توسط Gunnar Hjalmarsson
استفاده از زمان::محلی;
my $today = timelocal 0, 0, 12, ( localtime )[3..5];
my ($d، $m، $y) = ( زمان محلی $today-86400 )[3..5]; # اشتباه
printf "دیروز: %d-%02d-%02d\n"، $y+1900، $m+1، $d;
میکند پرل داشته باشد a سال 2000 or 2038 مشکل؟ Is پرل Y2K سازگار؟
(با مشارکت برایان دی فوی)
پرل خود هرگز مشکل Y2K نداشت، اگرچه این مسئله هرگز مانع از ایجاد Y2K نشد
مشکلات خود به خود برای استفاده مناسب، به مستندات "زمان محلی" مراجعه کنید.
با شروع Perl 5.12، "localtime" و "gmtime" می توانند تاریخ های گذشته 03:14:08 ژانویه را مدیریت کنند.
19، 2038، زمانی که یک زمان مبتنی بر 32 بیت سرریز می شد. هنوز ممکن است یک هشدار در مورد a دریافت کنید
پرل 32 بیتی:
% perl5.12 -E 'say scalar localtime( 0x9FFF_FFFFFFFF )'
سرریز اعداد صحیح در عدد هگزادسیمال در -e خط 1.
چهارشنبه 1 نوامبر 19:42:39 5576711
در یک «پرل» 64 بیتی، میتوانید تاریخهای بزرگتری را برای آن پروژههای واقعا طولانیتر دریافت کنید:
% perl5.12 -E 'say scalar gmtime( 0x9FFF_FFFFFFFF )'
پنجشنبه 2 نوامبر 00:42:39 5576711
اگر بخواهید پروتون های در حال فروپاشی را پیگیری کنید، هنوز شانس ندارید.
داده ها: رشته
چگونه do I معتبر ساختن ورودی؟
(با مشارکت برایان دی فوی)
راههای زیادی برای اطمینان از اینکه ارزشها همان چیزی هستند که انتظار دارید یا میخواهید بپذیرید وجود دارد. بعلاوه
نمونه های خاصی را که در perlfaq پوشش می دهیم، می توانید به ماژول ها نیز نگاه کنید
"Assert" و "Validate" در نام آنها به همراه ماژول های دیگری مانند Regexp::Common.
برخی از ماژول ها دارای اعتبارسنجی برای انواع خاصی از ورودی هستند، مانند Business::ISBN،
کسب و کار:: کارت اعتباری، ایمیل:: معتبر، و داده:: اعتبارسنجی:: IP.
چگونه do I فرار کردن a رشته؟
بستگی دارد که منظور شما از "فرار" چیست. فرارهای URL در perlfaq9 بررسی می شوند. پوسته
Escape ها با کاراکتر بک اسلش ("\") با حذف می شوند
s/\\(.)/$1/g;
این "\n" یا "\t" یا هر گریز خاص دیگری را گسترش نمیدهد.
چگونه do I برداشتن متوالی جفت of شخصیت ها؟
(با مشارکت برایان دی فوی)
شما می توانید از عملگر جایگزینی برای پیدا کردن جفت کاراکترها (یا اجرای کاراکترها) استفاده کنید.
و آنها را با یک نمونه جایگزین کنید. در این جایگزینی، شخصیتی را در می یابیم
"(.)". پرانتزهای حافظه کاراکتر تطبیق داده شده را در مرجع پشتی "\g1" ذخیره می کنند
ما از آن استفاده می کنیم تا بخواهیم همان چیز بلافاصله دنبال شود. آن قسمت را جایگزین می کنیم
رشته با کاراکتر در $1.
s/(.)\g1/$1/g;
همچنین می توانیم از عملگر نویسه گردانی "tr///" استفاده کنیم. در این مثال، لیست جستجو
سمت "tr///" ما حاوی چیزی نیست، اما گزینه "c" مکمل آن است
همه چیز. لیست جایگزینی نیز حاوی چیزی نیست، بنابراین نویسهگردانی تقریباً a است
no-op زیرا هیچ جایگزینی انجام نمی دهد (یا دقیق تر، کاراکتر را با آن جایگزین کنید
خودش). با این حال، گزینه "s" کاراکترهای تکراری و متوالی را در قسمت له می کند
رشته تا یک کاراکتر در کنار خودش نشان داده نشود
my $str = 'هارلم'; # در هلند
$str =~ tr///cs; # حالا هارلم، مثل نیویورک
چگونه do I گسترش تابع تماس in a رشته؟
(با مشارکت برایان دی فوی)
این در perlref مستند شده است، و اگرچه خواندن آن آسانترین کار نیست، اما اینطور است
کار در هر یک از این مثال ها، تابع داخل بریس های استفاده شده را به فراخوانی می کنیم
ارجاع دادن به یک مرجع اگر بیش از یک مقدار برگشتی داشته باشیم، می توانیم و را بسازیم
ارجاع دادن به یک آرایه ناشناس در این مورد، تابع را در متن فهرست فراخوانی می کنیم.
چاپ "مقادیر زمانی @{ [localtime] } هستند.\n";
اگر بخواهیم تابع را در زمینه اسکالر فراخوانی کنیم، باید کمی کار بیشتری انجام دهیم. ما میتوانیم
واقعاً هر کدی را که دوست داریم در داخل بریس ها داریم، بنابراین به سادگی باید با اسکالر پایان دهیم
مرجع، اگرچه نحوه انجام این کار به شما بستگی دارد، و می توانید از کد داخل بریس ها استفاده کنید.
توجه داشته باشید که استفاده از پرانتز یک زمینه لیست ایجاد می کند، بنابراین ما به "اسکالر" برای اجبار کردن نیاز داریم
زمینه اسکالر روی تابع:
چاپ "زمان ${\(زمان محلی اسکالر)} است.\n"
print "time is ${ my $x = localtime; \$x }.\n";
اگر تابع شما قبلاً یک مرجع را برمی گرداند، نیازی به ایجاد مرجع ندارید
خودتان.
علامت زمانی فرعی { my $t = localtime; \$t }
چاپ "زمان ${ timestamp() } است.\n";
ماژول "Interpolation" نیز می تواند جادوهای زیادی را برای شما انجام دهد. می توانید یک متغیر مشخص کنید
نام، در این مورد "E"، برای راه اندازی یک هش گره خورده که درون یابی را برای شما انجام می دهد. این دارد
چندین روش دیگر نیز برای انجام این کار.
استفاده از درون یابی E => 'eval';
چاپ "مقادیر زمانی $E{localtime()} هستند.\n";
در بیشتر موارد، احتمالاً استفاده از الحاق رشتهها آسانتر است، که باعث ایجاد نیرو نیز میشود
زمینه اسکالر
چاپ "زمان است". زمان محلی() . ".\n";
چگونه do I پیدا کردن تطبیق / تودرتو هر چیزی؟
برای پیدا کردن چیزی بین دو کاراکتر واحد، الگویی مانند "/x([^x]*)x/"
بیت های مداخله ای در 1 دلار. برای چندین مورد، پس چیزی بیشتر شبیه "/alpha(.*?)omega/"
مورد نیاز خواهد بود. برای الگوهای تو در تو و/یا عبارات متعادل، به اصطلاح را ببینید
ساختار (?PARNO) (در دسترس از Perl 5.10). ماژول CPAN Regexp::Common می تواند کمک کند
برای ساخت چنین عبارات منظم (به ویژه Regexp::Common::balanced و
Regexp:: مشترک:: محدود).
موارد پیچیده تر نیاز به نوشتن تجزیه کننده دارند، احتمالاً با استفاده از یک ماژول تجزیه از
CPAN مانند Regexp::Grammars، Parse::RecDescent، Parse::Yapp، Text::Balanced یا Marpa::R2.
چگونه do I معکوس a رشته؟
همانطور که در "reverse" در perlfunc مستند شده است از "reverse()" در زمینه اسکالر استفاده کنید.
my $reversed = معکوس $string;
چگونه do I گسترش زبانه ها in a رشته؟
می توانید خودتان این کار را انجام دهید:
1 while $string =~ s/\t+/' ' x (طول($&) * 8 - طول($`) % 8)/e;
یا فقط می توانید از ماژول Text::Tabs (بخشی از توزیع استاندارد Perl) استفاده کنید.
استفاده از Text::Tabs;
my @expanded_lines = expand(@lines_with_tabs);
چگونه do I اصلاح مجدد a پاراگراف؟
استفاده از متن:: Wrap (بخشی از توزیع استاندارد Perl):
استفاده از Text::Wrap;
print wrap("\t", ' ', @paragraphs);
پاراگراف هایی که به Text::Wrap می دهید نباید حاوی خطوط جدید تعبیه شده باشد. متن::پیچیدن
خطوط را توجیه نمی کند (تراز-راست).
یا از ماژول CPAN Text::Autoformat استفاده کنید. قالب بندی فایل ها را می توان به راحتی با ساختن یک
نام مستعار پوسته، مانند:
نام مستعار fmt="perl -i -MText::Autoformat -n0777
-e 'print autoformat $_, {all=>1}' $*"
به مستندات Text::Autoformat مراجعه کنید تا از قابلیت های فراوان آن مطلع شوید.
چگونه می توان I دسترسی or تغییر دادن N کاراکتر of a رشته؟
با استفاده از آن می توانید به اولین کاراکترهای یک رشته دسترسی داشته باشید substr(). برای بدست آوردن اولین
برای مثال، کاراکتر از موقعیت 0 شروع کنید و رشته ای به طول 1 را بگیرید.
my $string = "فقط یک هکر پرل دیگر";
my $first_char = substr($string, 0, 1 ); # 'J'
برای تغییر بخشی از یک رشته، می توانید از آرگومان چهارم اختیاری استفاده کنید
رشته جایگزین
substr($string, 13, 4, "Perl 5.8.0" );
VOUS استفاده pouvez aussi substr() به عنوان یک مقدار
substr( $string, 13, 4 ) = "Perl 5.8.0";
چگونه do I تغییر دادن la نهم وقوع of چیزی؟
شما باید N را خودتان پیگیری کنید. به عنوان مثال، فرض کنید می خواهید پنجمی را تغییر دهید
وقوع «هر کس» یا «هر که» به «هرکس» یا «هر که باشد»، مورد
بی احساس همه اینها فرض می کنند که $_ حاوی رشته ای است که باید تغییر داده شود.
$ تعداد = 0؛
s{((چه کسی؟)هرگز)}{
++$count == 5 # آیا پنجمین است؟
? "${2}همچنین" # بله، تعویض شود
: $1 # renege و آن را رها کنید
}ige;
در حالت کلی تر، می توانید از اصلاح کننده "/g" در یک حلقه "while" با حفظ شمارش استفاده کنید.
از مسابقات
$WANT = 3;
$ تعداد = 0؛
$_ = "یک ماهی دو ماهی قرمز ماهی آبی";
در حالی که (/(\w+)\s+fish\b/gi) {
اگر (++$count == $خواهم) {
چاپ "ماهی سوم یک دلار است.\n";
}
}
که چاپ می شود: "ماهی سوم یک ماهی قرمز است." همچنین می توانید از تعداد تکرار و
الگوی تکراری مانند این:
/(?:\w+\s+fish\s+){2}(\w+)\s+fish/i;
چگونه می توان I تعداد دفعات مشاهده la عدد of ظهور of a بستر در داخل a رشته؟
چندین راه وجود دارد که بازدهی متفاوتی دارند. اگر می خواهید تعداد خاصی داشته باشید
تک کاراکتر (X) در یک رشته، میتوانید از تابع "tr///" مانند زیر استفاده کنید:
my $string = "ThisXlineXhasXsomeXx'sXinXit";
تعداد $ من = ($string =~ tr/X//);
چاپ "$count X کاراکتر در رشته وجود دارد";
این خوب است اگر فقط به دنبال یک شخصیت واحد هستید. با این حال، اگر در تلاش هستید
چندین زیر رشته کاراکتر را در یک رشته بزرگتر بشمارید، "tr///" کار نخواهد کرد. آنچه تو
می توان انجام داد بسته بندی است در حالی که() دور یک تطابق الگوی جهانی حلقه بزنید. مثلاً حساب کنیم
اعداد صحیح منفی:
my $string = "-9 55 48 -2 23 -76 4 14 -44";
تعداد $ من = 0;
while ($string =~ /-\d+/g) { $count++ }
چاپ "در رشته اعداد منفی $count وجود دارد";
نسخه دیگری از یک تطابق سراسری در زمینه فهرست استفاده می کند، سپس نتیجه را به یک اسکالر اختصاص می دهد.
تولید شمارشی از تعداد مسابقات
من $count = () = $string =~ /-\d+/g;
چگونه do I سرمایه گذاری تمام la کلمات on یک خط؟
(با مشارکت برایان دی فوی)
متن دامیان کانوی:: فرمت خودکار تمام تفکرات شما را مدیریت می کند.
استفاده از Text::Autoformat;
my $x = "Dr. Strangelove or: How I Learned to Stop".
"نگران و عاشق بمب"؛
چاپ $x، "\n";
برای $style من (qw( برجسته عنوان جمله )) {
فرمت خودکار چاپ ($x, { case => $style }), "\n";
}
چگونه می خواهید آن کلمات را با حروف بزرگ بنویسید؟
FRED AND BARNEY'S LODGE # تمام حروف بزرگ
مورد عنوان #Fred And Barney's Lodge
مورد برجسته Fred and Barney's Lodge #
این مشکل به این راحتی که به نظر می رسد نیست. فکر می کنید چند کلمه در آن وجود دارد؟ صبر کن
آن را ... منتظر آن .... اگر جواب 5 را دادید، درست می گویید. کلمات پرل گروه هایی از "\w+" هستند، اما
این چیزی نیست که شما می خواهید از آن استفاده کنید. پرل چگونه باید بداند که حروف بزرگ نباشد
که "s" بعد از آپستروف؟ می توانید یک عبارت منظم را امتحان کنید:
$string =~ s/ (
(^\w) #در ابتدای خط
| # یا
(\s\w) #قبل از فضای سفید
)
/\U$1/xg;
$string =~ s/([\w']+)/\u\L$1/g;
حالا، اگر نمیخواهید آن «و» را با حروف بزرگ بنویسید، چه؟ فقط از Text::Autoformat استفاده کنید و وارد شوید
با مشکل بعدی :)
چگونه می توان I انشعاب a [شخصیت]-محدود شده رشته جز چه زمانی داخل [شخصیت]؟
چندین ماژول می توانند این نوع تجزیه را انجام دهند - متن::متوازن، متن::CSV، متن::CSV_XS،
و متن::ParseWords، در میان دیگران.
مثالی از تلاش برای تقسیم رشته ای که با کاما به آن جدا شده است را در نظر بگیرید
زمینه های مختلف شما نمی توانید از "split(/,/)" استفاده کنید زیرا اگر کاما باشد نباید تقسیم کنید.
داخل نقل قول ها به عنوان مثال، یک خط داده مانند زیر بگیرید:
SAR001"""""Cimetrix، Inc"، "Bob Smith"، "CAM"،"N,8,1,0,7, "Error, Core Dumped"
به دلیل محدودیت نقل قول ها، این یک مشکل نسبتاً پیچیده است. خوشبختانه ما
جفری فریدل، نویسنده تسلط منظم عبارات، اینها را برای ما مدیریت کند. او
پیشنهاد می کند (با فرض اینکه رشته شما در $text باشد):
من @new = ();
push(@new، $+) در حالی که $text =~ m{
"([^\"\\]*(?:\\.[^\"\\]*)*)"،؟ # عبارت را در داخل نقل قول ها گروه بندی می کند
| ([^،]+)،؟
| ،
}gx;
push(@new، undef) if substr($text,-1,1) eq ',';
اگر میخواهید علامتهای نقل قول را در یک فیلد محدود شده با علامت نقل قول نشان دهید، فرار کنید
آنها را با اسلش معکوس (به عنوان مثال، "مانند \"this\").
متناوبا، ماژول Text::ParseWords (بخشی از توزیع استاندارد Perl) به شما اجازه می دهد
شما بگو:
استفاده از متن::ParseWords;
@new = quotewords(""، 0، $text);
برای تجزیه یا تولید CSV، به جای اجرای آن، از Text::CSV استفاده کنید
خودتان به شدت توصیه می شود؛ شما خود را از اشکالات عجیب و غریب که بعداً ظاهر می شوند صرفه جویی می کنید
با استفاده از کدی که قبلاً برای سالها در تولید آزمایش و آزمایش شده است.
چگونه do I نوار سفید فضا از جانب la آغاز/پایان of a رشته؟
(با مشارکت برایان دی فوی)
یک جایگزین می تواند این کار را برای شما انجام دهد. برای یک خط، میخواهید همه خطوط پیشرو را جایگزین کنید
یا فضای خالی دنباله دار بدون هیچ چیز. شما می توانید این کار را با یک جفت جایگزین انجام دهید:
s/^\s+//;
s/\s+$//;
شما همچنین می توانید آن را به عنوان یک جایگزین بنویسید، اگرچه ترکیب شده است
بیانیه کندتر از موارد جداگانه است. اگرچه ممکن است برای شما مهم نباشد:
s/^\s+|\s+$//g;
در این عبارت منظم، تناوب یا در ابتدا یا انتهای آن مطابقت دارد
رشته از آنجایی که لنگرها اولویت کمتری نسبت به تناوب دارند. با "/g"
پرچم، تعویض همه مسابقات ممکن را انجام می دهد، بنابراین هر دو را دریافت می کند. به یاد داشته باشید، دنباله دار
خط جدید با "\s+" مطابقت دارد و لنگر "$" می تواند با انتهای مطلق آن مطابقت داشته باشد
رشته، بنابراین خط جدید نیز ناپدید می شود. فقط خط جدید را به خروجی اضافه کنید که دارای این است
مزایای اضافه شده حفظ خطوط "خالی" (شامل کامل از فضای خالی) که
"^\s+" همه را به خودی خود حذف می کند:
در حالی که ( <> ) {
s/^\s+|\s+$//g;
چاپ "$_\n"؛
}
برای یک رشته چند خطی، می توانید عبارت منظم را به هر خط منطقی در آن اعمال کنید
با افزودن پرچم "/m" (برای "چند خط") رشته کنید. با پرچم "/m"، "$" مطابقت دارد
قبل از یک خط جدید تعبیه شده، بنابراین آن را حذف نمی کند. این الگو هنوز هم حذف می کند
خط جدید در انتهای رشته:
$string =~ s/^\s+|\s+$//gm;
به یاد داشته باشید که خطوطی که کاملاً از فضای خالی تشکیل شده اند، از قسمت اول ناپدید می شوند
تناوب می تواند با کل رشته مطابقت داشته باشد و آن را با هیچ چیز جایگزین کند. اگه نیاز داشتی به
خطوط خالی جاسازی شده را حفظ کنید، باید کمی بیشتر کار کنید. به جای تطبیق هر کدام
فضای سفید (از آنجایی که شامل یک خط جدید است)، فقط با فضای سفید دیگر مطابقت دهید:
$string =~ s/^[\t\f ]+|[\t\f ]+$//mg;
چگونه do I لایی a رشته با جای خالی or لایی a عدد با صفر؟
در مثالهای زیر، $pad_len طولی است که میخواهید رشته را به آن اضافه کنید.
$text یا $num شامل رشته ای است که قرار است اضافه شود و $pad_char حاوی padding است.
شخصیت. می توانید به جای $pad_char از یک ثابت رشته کاراکتری استفاده کنید
متغیر اگر از قبل بدانید چیست. و به همین ترتیب می توانید از یک عدد صحیح در استفاده کنید
جای $pad_len اگر از قبل طول پد را بدانید.
ساده ترین روش از تابع "sprintf" استفاده می کند. این می تواند در سمت چپ یا راست با پد
خالی و در سمت چپ با صفر و نتیجه را کوتاه نمی کند. بسته"
تابع فقط میتواند رشتههای سمت راست را با موارد خالی اضافه کند و نتیجه را به کوتاه کند
حداکثر طول $pad_len.
# لایهبندی سمت چپ رشته با جاهای خالی (بدون برش):
my $padded = sprintf("%${pad_len}s", $text);
my $padded = sprintf("%*s", $pad_len, $text); #همین چیز
# اضافه کردن رشته به سمت راست با جاهای خالی (بدون برش):
my $padded = sprintf("%-${pad_len}s", $text);
my $padded = sprintf("%-*s", $pad_len, $text); #همین چیز
# اضافه کردن یک عدد به سمت چپ با 0 (بدون برش):
my $padded = sprintf("%0${pad_len}d"، $num);
my $padded = sprintf("%0*d", $pad_len, $num); #همین چیز
# اضافه کردن سمت راست رشته با جاهای خالی با استفاده از بسته (قطع خواهد شد):
my $padded = pack("A$pad_len",$text);
اگر نیاز دارید که نویسهای غیر از خالی یا صفر را با نویسه اضافه کنید، میتوانید از یکی از آنها استفاده کنید
روش های زیر همه آنها یک رشته پد با عملگر "x" تولید می کنند و آن را ترکیب می کنند
با متن $. این روش ها $text را کوتاه نمی کنند.
بال زدن چپ و راست با هر کاراکتری، ایجاد یک رشته جدید:
my $padded = $pad_char x ( $pad_len - length( $text ) ). $text;
my $padded = $text . $pad_char x ( $pad_len - length( $text ) );
padding چپ و راست با هر کاراکتری، تغییر مستقیم $text:
substr( $text, 0, 0 ) = $pad_char x ( $pad_len - length( $text ) );
$text .= $pad_char x ( $pad_len - length( $text ) );
چگونه do I عصاره انتخاب شد ستون ها از جانب a رشته؟
(با مشارکت برایان دی فوی)
اگر ستون های حاوی داده را می شناسید، می توانید از "substr" برای استخراج یک تک استفاده کنید
ستون.
my $column = substr($line, $start_column, $length );
اگر ستونها با فضای خالی یا جداکننده دیگری از هم جدا شده باشند، میتوانید از «split» استفاده کنید
تا زمانی که فضای خالی یا جداکننده نتواند به عنوان بخشی از داده ظاهر شود.
my $line = 'فرد بارنی بتی';
my @columns = split /\s+/, $line;
# ( ''، 'فرد'، 'بارنی'، 'بتی');
my $line = 'فرد||بارنی||بتی';
my @columns = split /\|/, $line;
# ( 'فرد'، ''، 'بارنی'، ''، 'بتی');
اگر می خواهید با مقادیر جدا شده با کاما کار کنید، این کار را انجام ندهید زیرا آن فرمت کمی است
پیچیده تر. از یکی از ماژول هایی استفاده کنید که آن فرمت را مدیریت می کند، مانند Text::CSV،
متن::CSV_XS یا متن::CSV_PP.
اگر میخواهید یک خط کامل از ستونهای ثابت را جدا کنید، میتوانید از «unpack» با آن استفاده کنید
فرمت A (ASCII). با استفاده از یک عدد بعد از مشخص کننده فرمت، می توانید ستون را مشخص کنید
عرض برای جزئیات بیشتر به ورودیهای "pack" و "unpack" در perlfunc مراجعه کنید.
my @fields = unpack( $line, "A8 A8 A8 A16 A4" );
توجه داشته باشید که فاصلههای موجود در آرگومان قالب برای «باز کردن بستهبندی» نشاندهنده فاصلههای تحت اللفظی نیستند. اگر شما
داده های جدا شده از فضا داشته باشید، ممکن است بخواهید به جای آن "تقسیم" کنید.
چگونه do I پیدا کردن la ساندکس ارزش of a رشته؟
(با مشارکت برایان دی فوی)
می توانید از ماژول "Text::Soundex" استفاده کنید. اگر می خواهید تطبیق فازی یا نزدیک انجام دهید، می توانید
همچنین ممکن است ماژول های String::Approx و Text::Metaphone و Text::DoubleMetaphone را امتحان کنید.
چگونه می توان I گسترش متغیرها in متن رشته های؟
(با مشارکت برایان دی فوی)
اگر میتوانید از آن اجتناب کنید، انجام ندهید، یا اگر میتوانید از یک سیستم قالب، مانند Text::Template استفاده کنید.
یا قالب ابزار، به جای آن این کار را انجام دهید. حتی ممکن است بتوانید کار را انجام دهید
"sprintf" یا "printf":
my $string = sprintf 'به %s و %s سلام کنید', $foo, $bar;
با این حال، برای یک مورد ساده که در آن من نمی خواهم یک الگوی کامل را بیرون بکشم
سیستم، من از رشته ای استفاده خواهم کرد که دارای دو متغیر اسکالر پرل در آن است. در این مثال، من
می خواهید $foo و $bar را به مقادیر متغیر خود گسترش دهید:
my $foo = 'فرد';
my $bar = 'بارنی';
$string = 'به $foo و $bar سلام کنید';
یکی از راه هایی که می توانم این کار را انجام دهم شامل عملگر جایگزین و یک پرچم دوتایی "/e" است. اولین
"/e" $1 را در سمت جایگزین ارزیابی می کند و آن را به $foo تبدیل می کند. /e دوم شروع می شود
با $foo و ارزش آن را جایگزین می کند. سپس $foo به "فرد" تبدیل می شود، و این
در نهایت آنچه در رشته باقی می ماند:
$string =~ s/(\$\w+)/$1/eeg; # 'به فرد و بارنی سلام برسان'
"/e" نیز بیصدا نقضهای سختگیرانه را نادیده میگیرد و جایگزین متغیر تعریفنشده میشود.
اسامی با رشته خالی از آنجایی که من از پرچم "/e" استفاده می کنم (دو بار زوج!)، همه را دارم
همان مشکلات امنیتی که من با "eval" به شکل رشته ای آن دارم. اگر چیز عجیبی باشد
در $foo، شاید چیزی شبیه "@{[ system "rm -rf /" ]}، سپس میتوانم خودم را وارد کنم
مشکل.
برای دور زدن مشکل امنیتی، میتوانم مقادیر را به جای هش از هش بیرون بکشم
ارزیابی نام متغیرها با استفاده از یک "/e"، می توانم هش را برای اطمینان از مقدار بررسی کنم
وجود دارد، و اگر وجود نداشت، میتوانم مقدار گمشده را با یک نشانگر جایگزین کنم، در این مورد
"؟؟؟" برای نشان دادن اینکه چیزی را از دست داده ام:
my $string = 'این $foo و $bar دارد';
% جایگزین های من = (
foo => 'فرد'،
);
# $string =~ s/\$(\w+)/$Replacements{$1}/g;
$string =~ s/\$(\w+)/
آیا $Replacements{$1} وجود دارد؟ $Replacements{$1} : "???"
/به عنوان مثال؛
چاپ $string;
چه خبر اشتباه با همیشه به نقل از "$vars"؟
مشکل این است که آن نقل قولهای دوگانه، رشتهبندی را مجبور میکنند - اعداد اجباری و
ارجاع به رشته ها -- حتی زمانی که نمی خواهید آنها رشته ای باشند. به این فکر کن
way: از بسط دو نقل قول برای تولید رشته های جدید استفاده می شود. اگر از قبل یک رشته دارید،
چرا بیشتر نیاز دارید؟
اگر به نوشتن چیزهای عجیب و غریب مانند این عادت کرده اید:
چاپ "$var"; #بد
my $new = "$old"; #بد
somefunc("$var"); #بد
دچار مشکل خواهید شد آنها باید (در 99.8٪ موارد) ساده تر و مستقیم تر باشند:
چاپ $var;
من $جدید = $قدیم;
somefunc($var);
در غیر این صورت، علاوه بر اینکه سرعت شما را کاهش میدهد، زمانی که چیزی در آن قرار دارد، کد را میشکنید
اسکالر در واقع نه رشته است و نه عدد، بلکه یک مرجع است:
func(\@array);
تابع فرعی {
من $aref = shift;
my $oref = "$aref"; # اشتباه
}
شما همچنین می توانید در مورد چند عملیات پرل که واقعاً انجام می دهند، با مشکلات ظریفی مواجه شوید
به تفاوت بین یک رشته و یک عدد، مانند "++" جادویی اهمیت دهید.
اپراتور افزایش خودکار یا syscall() تابع.
Stringification آرایه ها را نیز از بین می برد.
خطوط @ من = `فرمان`;
چاپ "@lines"؛ # اشتباه - جای خالی اضافی
چاپ @lines; # درست
چرا نکن my < اسناد و مدارک کار می کند؟
در اینجا اسناد در perlop یافت می شود. این سه مورد را بررسی کنید:
بعد از قسمت << نباید فاصله ای وجود داشته باشد.
(احتمالاً) باید یک نقطه ویرگول در انتهای نشانه باز وجود داشته باشد
شما نمی توانید (به راحتی) هیچ فضایی در مقابل تگ داشته باشید.
حداقل باید یک جداکننده خط بعد از نشانه پایان وجود داشته باشد.
اگر می خواهید متن را در سند اینجا تورفتگی کنید، می توانید این کار را انجام دهید:
# همه در یک
(VAR $ من = <
نوشته ی تو
اینجا می رود
HERE_TARGET
اما HERE_TARGET همچنان باید در مقابل حاشیه باشد. اگر می خواهید که تورفتگی داشته باشد
همچنین، شما باید در تورفتگی نقل قول کنید.
(من نقل قول $ = <<' FINIS') =~ s/^\s+//gm;
... وقتی تو و همه کارهایت آرامش داشته باشی، آرامش خواهیم داشت
از بین رفت - و کارهای ارباب تاریک خود را که شما به او
ما را تحویل می دهد تو دروغگو، سارومان، و مفسد هستی
از قلب مردان --Theoden در /usr/src/perl/taint.c
FINIS
$quote =~ s/\s+--/\n--/;
یک تابع ثابت کننده-بالا همه منظوره خوب برای اسناد تورفتگی در اینجا به شرح زیر است. آی تی
انتظار دارد که با یک سند اینجا به عنوان آرگومان فراخوانی شود. به نظر می رسد ببیند که آیا هر کدام
خط با یک زیررشته مشترک شروع می شود، و اگر چنین است، آن رشته فرعی را حذف می کند. در غیر این صورت، آن را
مقدار فضای خالی اصلی موجود در خط اول را می گیرد و آن مقدار را حذف می کند
هر خط بعدی
اصلاح فرعی {
محلی $_ = shift;
my ($سفید، $leader)؛ # فضای خالی مشترک و رشته پیشرو مشترک
if (/^\s*(?:([^\w\s]+)(\s*).*\n)(?:\s*\g1\g2?.*\n)+$/) {
($white، $leader) = ($2، quotemeta($1));
} دیگری {
($white، $leader) = (/^(\s+)/، '');
}
s/^\s*?$leader(?:$white)?//gm;
بازگشت $_;
}
این با رشته های ویژه پیشرو که به صورت پویا تعیین می شود کار می کند:
$remember_the_main = رفع<<' MAIN_INTERPRETER_LOOP';
@@@ بین المللی
@@@ runops() {
@@@ SAVEI32 (سطح اجرا)؛
@@@ runlevel++;
@@@ while ( op = (*op->op_ppaddr)() );
@@@ TAINT_NOT;
@@@ بازگشت 0;
@@@ }
MAIN_INTERPRETER_LOOP
یا با مقدار ثابتی از فضای سفید پیشرو، با تورفتگی باقیمانده به درستی
حفظ شده:
من $شعر = تعمیر<
اکنون خیلی جلوتر است که جاده رفته است ،
و اگر می توانم باید دنبال کنم ،
با پای مشتاق دنبال آن
تا اینکه به یک روش بزرگتر بپیوندد
جایی که بسیاری از مسیرها و کارها به هم می رسند.
و پس کجا؟ من نمی توانم بگویم.
--Bilbo در /usr/src/perl/pp_ctl.c
EVER_ON_AND_ON
داده ها: آرایه ها
چی is la تفاوت میان a فهرست و an آرایه؟
(با مشارکت برایان دی فوی)
لیست مجموعه ای ثابت از اسکالرها است. آرایه متغیری است که یک متغیر را نگه می دارد
مجموعه اسکالرها یک آرایه می تواند مجموعه خود را برای عملیات لیست تامین کند، بنابراین لیست کنید
عملیات روی آرایه ها نیز کار می کند:
# برش
( 'سگ'، 'گربه'، 'پرنده' )[2,3];
@حیوانات[2,3،XNUMX];
# تکرار
foreach ( qw( سگ گربه پرنده ) ) { ... }
foreach ( @animals ) { ... }
my @three = grep { length == 3 } qw( dog cat bird );
my @three = grep { length == 3 } @animals;
# یک لیست آرگومان تهیه کنید
wash_animals( qw( سگ گربه پرنده ) );
wash_animals( @animals );
عملیات آرایهای که اسکالرها را تغییر میدهند، آنها را مرتب میکنند، یا مقداری را اضافه یا کم میکنند
اسکالرها، فقط روی آرایه ها کار می کنند. اینها نمی توانند روی یک لیست کار کنند، که ثابت شده است. عملیات آرایه
شامل "shift"، "unshift"، "push"، "pop" و "splice" است.
یک آرایه همچنین می تواند طول خود را تغییر دهد:
$#حیوانات = 1; # کوتاه کردن به دو عنصر
$#حیوانات = 10000; # از قبل به 10,001 عنصر گسترش دهید
شما می توانید یک عنصر آرایه را تغییر دهید، اما نمی توانید یک عنصر لیست را تغییر دهید:
$animals[0] = 'Rottweiler';
qw( سگ گربه پرنده )[0] = 'Rottweiler'; # خطای نوشتاری کد!
foreach ( @animals ) {
s/^d/fr/; # خوب کار می کند
}
foreach ( qw ( سگ گربه پرنده ) ) {
s/^d/fr/; #خطا! تغییر مقدار فقط خواندنی!
}
با این حال، اگر عنصر لیست خود یک متغیر باشد، به نظر می رسد که می توانید یک لیست را تغییر دهید
عنصر با این حال، عنصر لیست متغیر است، نه داده. شما تغییر نمی دهید
عنصر لیست، اما چیزی که عنصر لیست به آن اشاره دارد. خود عنصر لیست اینطور نیست
تغییر: همچنان همان متغیر است.
شما همچنین باید مراقب زمینه باشید. شما می توانید یک آرایه را به یک اسکالر اختصاص دهید تا آن را بدست آورید
تعداد عناصر در آرایه اگرچه این فقط برای آرایه ها کار می کند:
من $count = @animals; # فقط با آرایه ها کار می کند
اگر سعی کنید همان کار را با لیستی که فکر می کنید انجام دهید، کاملاً متفاوت خواهید بود
نتیجه اگرچه به نظر می رسد که شما یک لیست در سمت راست دارید، پرل در واقع یک را می بیند
دسته ای از اسکالرها که با کاما از هم جدا شده اند:
my $scalar = ( 'سگ'، 'گربه'، 'پرنده'); # $scalar پرنده می شود
از آنجایی که شما به یک اسکالر اختصاص می دهید، سمت راست در زمینه اسکالر قرار دارد. کاما
عملگر (بله، یک عملگر است!) در زمینه اسکالر سمت چپ خود را ارزیابی می کند، پرتاب می کند
نتیجه را حذف می کند و سمت راست آن را ارزیابی می کند و نتیجه را برمی گرداند. در واقع، که
list-lookalike به $scalar آن را به سمت راست ترین مقدار اختصاص می دهد. بسیاری از مردم این را خراب می کنند زیرا
آنها فهرستی شبیه به فهرست را انتخاب می کنند که آخرین عنصر آن نیز تعداد مورد انتظارشان است:
my $scalar = ( 1, 2, 3 ); # اسکالر $ به طور تصادفی 3 می شود
چی is la تفاوت میان آرایه $[1] و @array[1]؟
(با مشارکت برایان دی فوی)
تفاوت در sigil است، آن کاراکتر خاص در جلوی نام آرایه. "$"
sigil به معنای "دقیقا یک مورد" است، در حالی که "@" sigil به معنای "صفر یا چند مورد" است. "$"
برای شما یک اسکالر واحد دریافت می کند، در حالی که "@" یک لیست به شما می دهد.
این سردرگمی به این دلیل به وجود می آید که افراد به اشتباه تصور می کنند که sigil نشان دهنده متغیر است
تایپ کنید
آرایه $[1] یک دسترسی تک عنصری به آرایه است. این مورد را به داخل برمی گرداند
index 1 (یا undef اگر موردی وجود ندارد). اگر قصد دارید دقیقاً یک عنصر را بدست آورید
از آرایه، این فرمی است که باید استفاده کنید.
آرایه@[1] یک برش آرایه است، اگرچه تنها یک شاخص دارد. می توانید بیرون بکشید
چندین عنصر به طور همزمان با تعیین شاخص های اضافی به عنوان یک لیست، مانند
@array[1,4,3,0،XNUMX،XNUMX،XNUMX].
با استفاده از یک برش در سمت چپ تکلیف، زمینه فهرست را در اختیار قرار می دهد
سمت راست. این می تواند منجر به نتایج غیرمنتظره شود. به عنوان مثال، اگر می خواهید یک را بخوانید
یک خط از یک filehandle، اختصاص دادن به یک مقدار اسکالر خوب است:
آرایه $[1] = ;
با این حال، در زمینه لیست، عملگر ورودی خط، تمام خطوط را به عنوان یک لیست برمی گرداند. در
خط اول به @array[1] می رود و بقیه خطوط به طور مرموزی ناپدید می شوند:
@array[1] = ; # به احتمال زیاد آن چیزی نیست که شما می خواهید
یا پراگما "هشدار استفاده" یا -w هنگامی که از یک برش آرایه استفاده می کنید، flag به شما هشدار می دهد
با یک شاخص واحد
چگونه می توان I برداشتن تکراری عناصر از جانب a فهرست or آرایه؟
(با مشارکت برایان دی فوی)
از هش استفاده کنید هنگامی که به کلمات "بی نظیر" یا "تکراری" فکر می کنید، به "کلیدهای هش" فکر کنید.
اگر به ترتیب عناصر اهمیتی نمی دهید، می توانید هش را ایجاد کنید
کلیدها را استخراج کنید این مهم نیست که چگونه آن هش را ایجاد می کنید: فقط از "کلیدها" استفاده می کنید
عناصر منحصر به فرد را دریافت کنید
من %hash = map { $_, 1 } @array;
# یا یک هش اسلایس: @hash{ @array } = ();
# یا یک foreach: $hash{$_} = 1 foreach ( @array );
my @unique = کلیدهای %hash;
اگر می خواهید از یک ماژول استفاده کنید، تابع "uniq" را از List::MoreUtils امتحان کنید. در زمینه فهرست
عناصر منحصر به فرد را برمی گرداند و ترتیب آنها را در لیست حفظ می کند. در زمینه اسکالر، آن
تعداد عناصر منحصر به فرد را برمی گرداند.
استفاده از لیست::MoreUtils qw(uniq);
my @unique = uniq( 1, 2, 3, 4, 4, 5, 6, 5, 7 ); # 1,2,3,4,5,6,7،XNUMX،XNUMX،XNUMX،XNUMX،XNUMX،XNUMX
my $unique = uniq( 1, 2, 3, 4, 4, 5, 6, 5, 7 ); # 7
همچنین میتوانید هر عنصر را مرور کنید و از مواردی که قبلاً دیدهاید صرفنظر کنید. از هش استفاده کنید
پیگیری کنید اولین باری که حلقه یک عنصر را می بیند، آن عنصر کلیدی در %Seen ندارد. را
عبارت "next" کلید را ایجاد می کند و بلافاصله از مقدار آن که "undef" است استفاده می کند
حلقه تا "فشار" ادامه می یابد و مقدار آن کلید را افزایش می دهد. دفعه بعد حلقه
همان عنصر را می بیند، کلید آن در هش وجود دارد و مقدار آن کلید درست است
(از آنجایی که 0 یا "undef" نیست)، بنابراین تکرار بعدی از آن تکرار می گذرد و حلقه به
عنصر بعدی
من @unique = ();
من %seen = ();
foreach my $elem ( @array ) {
بعدی اگر $seen{ $elem }++;
push @unique, $elem;
}
میتوانید با استفاده از grep که همین کار را انجام میدهد، این را به طور خلاصهتر بنویسید.
من %seen = ();
من @unique = grep {! $seen{ $_ }++ } @array;
چگونه می توان I گفتن چه a معین عنصر is موجود in a فهرست or آرایه؟
(بخش هایی از این پاسخ توسط آنو سیگل و برایان دی فوی ارائه شده است)
شنیدن کلمه "در" است inنشان می دهد که احتمالاً باید از هش استفاده می کردید، نه a
لیست یا آرایه، برای ذخیره داده های شما. هش ها برای پاسخ سریع به این سوال طراحی شده اند
به طور موثر آرایه ها نیستند.
همانطور که گفته شد، چندین راه برای نزدیک شدن به این موضوع وجود دارد. در پرل 5.10 به بعد، می توانید
از عملگر تطبیق هوشمند برای بررسی اینکه یک مورد در یک آرایه یا یک هش وجود دارد استفاده کنید:
استفاده از 5.010;
if( $item ~~ @array ) {
بگویید "آرایه حاوی $item است"
}
if( $item ~~ %hash ) {
بگویید "هش حاوی $item است"
}
با نسخه های قبلی پرل، باید کمی کار بیشتری انجام دهید. اگر قرار است بسازید
این پرس و جو چندین بار بیش از مقادیر دلخواه رشته، سریعترین راه احتمالا معکوس کردن است
آرایه اصلی و حفظ هش که کلیدهای آن مقادیر آرایه اول هستند:
my @blues = qw/ لاجوردی سرولئن فیروزه ای لاجورد لاجورد/;
%is_blue = ();
برای (@blues) {$is_blue{$_} = 1 }
اکنون میتوانید بررسی کنید که آیا $is_blue{$some_color} است یا خیر. شاید نگه داشتن آن ایده خوبی بود
بلوز در وهله اول همه در یک هش.
اگر مقادیر همه اعداد صحیح کوچک هستند، می توانید از یک آرایه نمایه شده ساده استفاده کنید. این نوع
یک آرایه فضای کمتری را اشغال می کند:
من @primes = (2، 3، 5، 7، 11، 13، 17، 19، 23، 29، 31)؛
@is_tiny_prime من = ();
برای (@primes) { $is_tiny_prime[$_] = 1 }
# یا به سادگی @istiny_prime[@primes] = (1) x @primes;
اکنون بررسی میکنید که آیا $is_tiny_prime[$some_number] یا خیر.
اگر مقادیر مورد نظر به جای رشته ها اعداد صحیح باشند، می توانید مقدار زیادی از آن را ذخیره کنید
در عوض با استفاده از رشته های بیت فاصله دهید:
my @articles = ( 1..10, 150..2000, 2017 );
unef $read;
برای (@articles) { vec($read,$_,1) = 1 }
اکنون بررسی کنید که آیا "vec($read,$n,1)" برای برخی از $n درست است یا خیر.
این روشها تستهای فردی سریع را تضمین میکنند، اما نیاز به سازماندهی مجدد دارند
لیست یا آرایه اصلی آنها فقط در صورتی جواب می دهند که مجبور باشید چندین مقدار را در برابر آن آزمایش کنید
همان آرایه
اگر فقط یک بار تست می کنید، ماژول استاندارد List::Util تابع "first" را صادر می کند.
به این منظور. زمانی که عنصر را پیدا کرد متوقف می شود. به زبان C نوشته شده است
سرعت، و معادل پرل آن مانند زیر روال زیر است:
اول فرعی (&@) {
my $code = shift;
برای هر (@_) {
بازگشت $_ if &{$code}();
}
unef;
}
اگر سرعت اهمیت چندانی ندارد، اصطلاح رایج از grep در زمینه اسکالر استفاده می کند (که برمی گردد
تعداد مواردی که شرایط خود را پشت سر گذاشتند) تا کل لیست را طی کنید. این دارد
با این حال، فایده این است که به شما بگوید تعداد موارد منطبق را پیدا کرده است.
من $is_there = grep $_ eq $whatever، @array;
اگر می خواهید در واقع عناصر منطبق را استخراج کنید، به سادگی از grep در زمینه لیست استفاده کنید.
من @matches = grep $_ eq $whatever, @array;
چگونه do I محاسبه کردن la تفاوت of دو آرایه ها؟ چگونه do I محاسبه کردن la تقاطع of دو
آرایه ها؟
از هش استفاده کنید در اینجا کدی برای انجام هر دو و بیشتر وجود دارد. فرض بر این است که هر عنصر در a منحصر به فرد است
آرایه داده شده:
my (@union، @intersection، @difference);
%count من = ();
foreach my $element (@array1، @array2) { $count{$element}++ }
foreach my $element (keys %count) {
فشار @union، $element;
فشار @{ $count{$element} > 1 ? \@تقاطع : \@difference }, $element;
}
توجه داشته باشید که این است متقارن تفاوت، یعنی همه عناصر در A یا B اما
نه در هر دو آن را به عنوان یک عملیات xor در نظر بگیرید.
چگونه do I آزمون چه دو آرایه ها or هش هستند برابر؟
با پرل 5.10 و بالاتر، اپراتور هوشمند مطابقت می تواند با کمترین پاسخ به شما پاسخ دهد
مقدار کار:
استفاده از 5.010;
if(@array1 ~~ @array2 ) {
بگویید "آرایه ها یکسان هستند"؛
}
if( %hash1 ~~ %hash2 ) # مقادیر را بررسی نمی کند! {
بگویید "کلیدهای هش یکسان هستند"؛
}
کد زیر برای آرایه های تک سطحی کار می کند. از مقایسه رشته ای و
رشته های خالی تعریف شده را از تعریف نشده متمایز نمی کند. اگر چیز دیگری دارید اصلاح کنید
نیاز دارد.
$are_equal = compare_arrays(\@frogs, \@toads);
زیر مقایسه_آرایه ها {
my ($ first, $second) = @_;
بدون هشدار؛ # ساکت کردن شکایات جعلی -w undef
بازگشت 0 مگر اینکه @$first == @$second;
برای ($i من = 0؛ $i < @$first؛ $i++) {
بازگشت 0 اگر $first->[$i] ne $second->[$i];
}
1 بازگشت؛
}
برای ساختارهای چند سطحی، ممکن است بخواهید از رویکردی شبیه به این استفاده کنید. از
ماژول CPAN FreezeThaw:
از FreezeThaw qw (cmpStr) استفاده کنید.
my @a = my @b = ( "این"، "آن"، [ "بیشتر"، "موارد" ] );
printf "a و b حاوی %s آرایه\n"،
cmpStr(\@a، \@b) == 0
? "همین"
: "ناهمسان"؛
این رویکرد همچنین برای مقایسه هش ها کار می کند. در اینجا ما دو متفاوت را نشان خواهیم داد
پاسخ می دهد:
از FreezeThaw qw (cmpStr cmpStrHard) استفاده کنید.
my %a = my %b = ( "this" => "that", "extra" => [ "more", "stuff" ] );
$a{EXTRA} = \%b;
$b{EXTRA} = \%a;
printf "a و b حاوی %s هش\n"،
cmpStr(\%a، \%b) == 0 ? "همان" : "متفاوت";
printf "a و b حاوی %s هش\n"،
cmpStrHard(\%a, \%b) == 0 ? "همان" : "متفاوت";
اولی گزارش می دهد که هر دو هش حاوی داده های یکسان هستند، در حالی که دومی
گزارش می دهد که ندارند. که شما ترجیح می دهید به عنوان یک تمرین به خواننده سپرده می شود.
چگونه do I پیدا کردن la اول صف عنصر برای که a شرط is درست است؟
برای پیدا کردن اولین عنصر آرایه ای که یک شرط را برآورده می کند، می توانید از "first()" استفاده کنید.
عملکرد در ماژول List::Util که با Perl 5.8 ارائه می شود. این مثال اولین مورد را پیدا می کند
عنصری که حاوی "Perl" است.
Use List::Util qw(first);
my $element = first { /Perl/ } @array;
اگر نمی توانید از List::Util استفاده کنید، می توانید حلقه خود را برای انجام همان کار بسازید. یک بار شما
عنصر را پیدا کنید، حلقه را با آخرین متوقف می کنید.
من $پیدا شد
foreach (@array) {
if( /Perl/ ) {$found = $_; آخر }
}
اگر ایندکس آرایه را می خواهید، از تابع "firstidx()" از "List::MoreUtils" استفاده کنید:
استفاده از لیست::MoreUtils qw(firstidx);
my $index = firstidx { /Perl/ } @array;
یا خودتان آن را بنویسید، در میان شاخص ها تکرار کنید و عنصر آرایه را در هر کدام بررسی کنید
ایندکس کنید تا زمانی که یکی را پیدا کنید که شرایط را برآورده کند:
my($found, $index ) = ( undef, -1 );
for( $i = 0; $i < @array; $i++ ) {
if($array[$i] =~ /Perl/ ) {
$found = $آرایه[$i];
$index = $i;
آخر؛
}
}
چگونه do I دسته مرتبط لیست؟
(با مشارکت برایان دی فوی)
آرایه های پرل اندازه ثابتی ندارند، بنابراین اگر فقط می خواهید به لیست های پیوندی نیاز ندارید
موارد را اضافه یا حذف کنید می توانید از عملیات آرایه مانند "فشار"، "پاپ"، "shift" و
"unshift" یا "Splice" برای انجام این کار.
با این حال، گاهی اوقات، لیستهای پیوندی میتوانند در موقعیتهایی مفید باشند که میخواهید یک را "تکه" کنید
آرایه بنابراین به جای یک آرایه بزرگ، تعداد زیادی آرایه کوچک داشته باشید. می توانید آرایه ها را نگه دارید
طولانیتر از بزرگترین شاخص آرایه پرل، آرایههای کوچکتر را بهطور جداگانه در رشتهای قفل کنید
برنامه ها، حافظه کمتری را مجدداً اختصاص دهید یا به سرعت عناصر را در وسط زنجیره قرار دهید.
استیو لمبارک در گفتگوی YAPC::NA 2009 خود با عنوان "Perly Linked Lists" جزئیات را بررسی می کند (
<http://www.slideshare.net/lembark/perly-linked-lists>)، اگرچه شما فقط می توانید از او استفاده کنید
LinkedList:: ماژول واحد.
چگونه do I دسته بخشنامه لیست؟
(با مشارکت برایان دی فوی)
اگر میخواهید بیپایان در یک آرایه بچرخید، میتوانید مدول ایندکس را افزایش دهید
تعداد عناصر آرایه:
my @array = qw(abc);
من $i = 0;
در حالی که (1) {
چاپ $array[ $i++ % @array ], "\n";
آخرین اگر $i > 20;
}
همچنین می توانید از Tie::Cycle برای استفاده از اسکالر استفاده کنید که همیشه عنصر بعدی را دارد
آرایه دایره ای:
استفاده از Tie::Cycle;
tie my $cycle, 'Tie::Cycle', [ qw( FFFFFF 000000 FFFF00 ) ];
چاپ چرخه $; # FFFFFF
چاپ چرخه $; # 000000
چاپ چرخه $; # FFFF00
آرایه::Iterator::Circular یک شی تکرار کننده برای آرایه های دایره ای ایجاد می کند:
از Array::Iterator::Circular;
my $color_iterator = آرایه::Iterator::Circular->new(
qw (قرمز سبز آبی نارنجی)
);
foreach ( 1 .. 20 ) {
چاپ $color_iterator->next، "\n";
}
چگونه do I مخلوط کردن an صف به طور تصادفی؟
اگر Perl 5.8.0 یا بالاتر را نصب کرده اید، یا اگر Scalar-List-Utils 1.03 یا دارید
بعداً نصب شد، می توانید بگویید:
Use List::Util 'shuffle';
@shuffled = shuffle(@list);
در غیر این صورت، می توانید از شافل Fisher-Yates استفاده کنید.
sub fisher_yates_shuffle {
من $deck = shift; # $deck یک مرجع به یک آرایه است
بازگشت مگر اینکه @$deck; # نباید خالی باشد!
من $i = @$deck;
در حالی که (--$i) {
my $j = int rand ($i+1);
@$deck[$i,$j] = @$deck[$j,$i];
}
}
# مجموعه mpeg من را به هم بزنید
#
@mpeg من = ;
fisher_yates_shuffle( \@mpeg ); @mpeg را در جای خود تصادفی کنید
چاپ @mpeg;
توجه داشته باشید که پیادهسازی فوق، برخلاف آرایهای را در جای خود به هم میریزد
"List::Util::shuffle()" که یک لیست را می گیرد و یک لیست مخلوط شده جدید را برمی گرداند.
احتمالاً الگوریتمهای به هم ریختن را دیدهاید که با استفاده از اسپلایس کار میکنند و بهطور تصادفی یکی دیگر را انتخاب میکنند
عنصر برای تعویض عنصر فعلی
ساند؛
@new = ();
@old = 1 .. 10; # فقط نسخه ی نمایشی
در حالی که (@old) {
push(@new، splice(@old، rand @old، 1));
}
این بد است زیرا splice قبلاً O(N) است، و از آنجایی که شما آن را N بار انجام می دهید، به تازگی اختراع کرده اید
یک الگوریتم درجه دوم؛ یعنی O(N**2). این مقیاس نیست، اگرچه پرل چنین است
کارآمد است که احتمالا تا زمانی که آرایه های نسبتا بزرگی نداشته باشید متوجه این موضوع نخواهید شد.
چگونه do I پردازش/تغییر هر عنصر of an آرایه؟
از "for"/"foreach" استفاده کنید:
برای (@ خطوط) {
s/foo/bar/; # آن کلمه را تغییر دهید
tr/XZ/ZX/; # آن حروف را عوض کنید
}
اینم یکی دیگه بیایید حجم های کروی را محاسبه کنیم:
من @volumes = @radii;
برای (@volumes) { # @volumes قسمتهای خود را تغییر داده است
$_ **= 3;
$_ *= (4/3) * 3.14159; # این ثابت خواهد بود
}
که همچنین می تواند با "map()" که برای تبدیل یک لیست به لیست دیگر ساخته شده است انجام شود:
من @volumes = نقشه {$_ ** 3 * (4/3) * 3.14159} @radii;
اگر می خواهید همین کار را برای تغییر مقادیر هش انجام دهید، می توانید از آن استفاده کنید
تابع "ارزش ها". از Perl 5.6 مقادیر کپی نشده اند، بنابراین اگر $orbit (in
در این مورد)، مقدار را تغییر می دهید.
برای $orbit من ( مقادیر %orbits ) {
($orbit **= 3) *= (4/3) * 3.14159;
}
قبل از پرل 5.6 "مقدار" کپی هایی از مقادیر را برمی گرداند، بنابراین کدهای قدیمی پرل اغلب
حاوی ساختارهایی مانند @orbits{keys %orbits} به جای "values %orbits" که در آن
هش باید اصلاح شود.
چگونه do I را انتخاب کنید a تصادفی عنصر از جانب an آرایه؟
از تابع "rand()" استفاده کنید (به "rand" در perlfunc مراجعه کنید):
my $index = rand @array;
my $element = $array[$index];
یا به سادگی:
my $element = $array[ rand @array ];
چگونه do I جایز N عناصر of a لیست؟
از ماژول List::Permutor در CPAN استفاده کنید. اگر لیست در واقع یک آرایه است، آن را امتحان کنید
الگوریتم:: ماژول Permute (همچنین در CPAN). این با کد XS نوشته شده است و بسیار کارآمد است:
استفاده از الگوریتم:: Permute;
my @array = 'a'..'d';
my $p_iterator = الگوریتم::Permute->new ( \@array );
while (my perm = $p_iterator->next) {
چاپ "جایگشت بعدی: (@perm)\n"؛
}
برای اجرای سریعتر، می توانید انجام دهید:
استفاده از الگوریتم:: Permute;
my @array = 'a'..'d';
الگوریتم::جایگزینی::جایگزینی {
چاپ "جایگشت بعدی: (@array)\n"؛
} @آرایه؛
در اینجا یک برنامه کوچک است که همه جایگشت های همه کلمات را در هر خط ایجاد می کند
ورودی الگوریتم تعبیه شده در تابع "permute()" در جلد 4 مورد بحث قرار گرفته است (هنوز
منتشر نشده) از Knuth's La هنر of کامپیوتر برنامه نويسي و در هر لیستی کار خواهد کرد:
#!/usr/bin/perl -n
# فیشر-کراز ژنراتور جایگشت را سفارش داد
جایگزینی فرعی (&@) {
my $code = shift;
my @idx = 0..$#_;
while ( $code->(@_[@idx]) ) {
my $p = $#idx;
--$p while $idx[$p-1] > $idx[$p];
من $q = $p یا بازگشت.
فشار @idx، اتصال معکوس @idx، $p;
++$q while $idx[$p-1] > $idx[$q];
@idx[$p-1,$q]=@idx[$q,$p-1];
}
}
جایگشت { print "@_\n" } split;
ماژول Algorithm::Loops همچنین توابع "NextPermute" و "NextPermuteNum" را ارائه می دهد.
که به طور موثر همه جایگشت های منحصر به فرد یک آرایه را پیدا می کند، حتی اگر دارای تکراری باشد
مقادیر، اصلاح آن در محل: اگر عناصر آن به ترتیب معکوس مرتب شوند، آرایه
معکوس می شود و مرتب می شود و false برمی گردد. در غیر این صورت جایگشت بعدی است
برگشت
"NextPermute" از ترتیب رشته ها و ترتیب عددی "NextPermuteNum" استفاده می کند، بنابراین می توانید شمارش کنید
همه جایگشت های 0..9 به این صورت است:
استفاده از الگوریتم::Loops qw(NextPermuteNum);
my @list= 0..9;
آیا { print "@list\n" } در حالی که NextPermuteNum @list;
چگونه do I نوع an صف by (هر چیزی)؟
یک تابع مقایسه را ارائه کنید مرتب سازی() (در "مرتب سازی" در perlfunc توضیح داده شده است):
@list = مرتب کردن { $a <=> $b } @list;
تابع مرتبسازی پیشفرض، cmp است، مقایسه رشتهها، که «(1، 2، 10)» را به
"(1، 10، 2)". "<=>" که در بالا استفاده شد، عملگر مقایسه عددی است.
اگر برای بیرون کشیدن بخشی که میخواهید مرتب کنید، عملکرد پیچیدهای دارید، پس
این کار را در تابع مرتب سازی انجام ندهید. ابتدا آن را بیرون بکشید، زیرا BLOCK مرتب سازی می تواند باشد
بارها برای یک عنصر فراخوانی شده است. در اینجا مثالی از نحوه بیرون کشیدن اولین مورد آورده شده است
کلمه بعد از اولین شماره در هر مورد، و سپس آن کلمات را بدون حساسیت به حروف مرتب کنید.
@idx من
برای (@data) {
مورد $ من;
($item) = /\d+\s*(\S+)/;
فشار @idx، uc($item);
}
my @sorted = @data[ sort { $idx[$a] cmp $idx[$b] } 0 .. $#idx ];
که می تواند به این شکل نیز نوشته شود، با استفاده از ترفندی که به نام the شناخته می شود
تبدیل شوارتزیان:
my @sorted = map { $_->[0] }
مرتب سازی {$a->[1] cmp $b->[1] }
map { [ $_, uc( (/\d+\s*(\S+)/)[0]) } @data;
اگر نیاز به مرتب سازی در چندین فیلد دارید، الگوی زیر مفید است.
من @sorted = مرتب سازی {
field1($a) <=> field1($b) ||
field2($a) cmp field2($b) ||
field3($a) cmp field3($b)
} @داده ها؛
این را می توان به راحتی با پیش محاسبه کلیدها که در بالا ذکر شد ترکیب کرد.
مشاهده نوع مقاله در مجموعه "بیشتر از آنچه می خواستید بدانید" در
<http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz> برای اطلاعات بیشتر در مورد این رویکرد.
همچنین به سوال بعدی در perlfaq4 در مورد مرتب سازی هش ها مراجعه کنید.
چگونه do I دستکاری آرایه ها of بیت ها؟
از "pack()" و "unpack()"، یا "vec()" و عملیات بیتی استفاده کنید.
به عنوان مثال، شما مجبور نیستید بیت های جداگانه را در یک آرایه ذخیره کنید (که به این معنی است
شما فضای زیادی را تلف می کنید). برای تبدیل یک آرایه از بیت ها به یک رشته، از "vec()" استفاده کنید
بیت های مناسب را تنظیم کنید به این ترتیب $vec فقط در صورتی که $ints[N] تنظیم شده باشد، بیت N را تنظیم میکند:
my @ints = (...); # آرایه بیت، به عنوان مثال (1، 0، 0، 1، 1، 0 ...)
من $vec = '';
foreach( 0 .. $#ints ) {
vec($vec,$_,1) = 1 اگر $ints[$_];
}
رشته $vec فقط به تعداد بیت هایی که نیاز دارد می گیرد. به عنوان مثال، اگر 16 داشتید
ورودیهای @ints، $vec فقط به دو بایت برای ذخیره آنها نیاز دارد (بدون احتساب اسکالر
سربار متغیر).
به این صورت است که با توجه به یک بردار در $vec، میتوانید آن بیتها را به آرایه @ints خود وارد کنید:
زیر bitvec_to_list {
من $vec = shift;
@ints من
# چگالی بایت تهی را پیدا کنید سپس بهترین الگوریتم را انتخاب کنید
اگر ($vec =~ tr/\0// / طول $vec > 0.95) {
استفاده از عدد صحیح؛
$i من
# این روش با اکثرا بایت های تهی سریعتر است
while($vec =~ /[^\0]/g ) {
$i = -9 + 8 * pos $vec;
فشار @ints، $i اگر vec($vec، ++$i، 1);
فشار @ints، $i اگر vec($vec، ++$i، 1);
فشار @ints، $i اگر vec($vec، ++$i، 1);
فشار @ints، $i اگر vec($vec، ++$i، 1);
فشار @ints، $i اگر vec($vec، ++$i، 1);
فشار @ints، $i اگر vec($vec، ++$i، 1);
فشار @ints، $i اگر vec($vec، ++$i، 1);
فشار @ints، $i اگر vec($vec، ++$i، 1);
}
}
دیگر {
# این روش یک الگوریتم عمومی سریع است
استفاده از عدد صحیح؛
my $bits = باز کردن بسته "b*", $vec;
فشار @ints، 0 اگر $bits =~ s/^(\d)// && $1;
فشار @ints، pos $bits while($bits =~ /1/g);
}
بازگشت \@ints;
}
این روش هر چه بردار بیت پراکنده تر باشد سریعتر می شود. (به لطف تیم بانس و
وینفرید کونیگ.)
با این پیشنهاد بنجامین گلدبرگ می توانید حلقه while را بسیار کوتاهتر کنید:
while($vec =~ /[^\0]+/g ) {
push @ints، grep vec($vec، $_، 1)، $-[0] * 8 .. $+[0] * 8;
}
یا از ماژول CPAN استفاده کنید Bit::Vector:
my $vector = Bit::Vector->new($num_of_bits);
$vector->Index_List_Store(@ints);
my @ints = $vector->Index_List_Read();
Bit::Vector روش های کارآمدی را برای بردار بیت، مجموعه ای از اعداد صحیح کوچک و "بزرگ" ارائه می دهد.
int" ریاضی.
در اینجا یک تصویر گسترده تر با استفاده از vec():
# نسخه ی نمایشی vec
my $vector = "\xff\x0f\xef\xfe";
چاپ "رشته ایلیا \\xff\\x0f\\xef\\xfe نشان دهنده عدد است"،
unpack("N"، $vector)، "\n";
my $is_set = vec($vector, 23, 1);
چاپ "بیت بیست و سوم آن" است، $is_set ? "set" : "clear", ".\n";
pvec($vector);
set_vec(1,1,1);
set_vec(3,1,1);
set_vec(23,1,1);
set_vec(3,1,3);
set_vec(3,2,3);
set_vec(3,4,3);
set_vec(3,4,7);
set_vec(3,8,3);
set_vec(3,8,7);
set_vec(0,32,17);
set_vec(1,32,17);
sub set_vec {
my ($offset، $width، $value) = @_;
من $بردار = '';
vec($vector، $offset، $width) = $value;
چاپ "offset=$offset width=$width value=$value\n";
pvec($vector);
}
زیر pvec {
من $بردار = shift;
my $bits = unpack("b*", $vector);
من $i = 0;
من $BASE = 8;
چاپ "طول بردار به بایت: ", length($vector), "\n";
@bytes = unpack("A8" x طول ($vector), $bits);
چاپ "بیت ها هستند: @bytes\n\n";
}
چرا میکند تعریف شده است() برگشت درست on خالی آرایه ها و هش؟
داستان کوتاه این است که شما احتمالا فقط باید از تعریف شده در اسکالرها یا توابع استفاده کنید، نه
روی انبوه ها (آرایه ها و هش ها). به "تعریف شده" در perlfunc در نسخه 5.004 یا نسخه های جدیدتر مراجعه کنید
از پرل برای جزئیات بیشتر.
داده ها: هاش ( انجمنی آرایه ها)
چگونه do I روند an تمام هش؟
(با مشارکت برایان دی فوی)
چند راه وجود دارد که می توانید کل هش را پردازش کنید. شما می توانید لیستی از
کلیدها، سپس از هر کلید عبور کنید، یا هربار یک جفت کلید-مقدار را بگیرید.
برای مرور همه کلیدها، از تابع "کلیدها" استفاده کنید. این همه کلیدهای را استخراج می کند
هش و آنها را به عنوان یک لیست به شما برمی گرداند. سپس می توانید مقدار را از طریق دریافت کنید
کلید خاصی که در حال پردازش هستید:
foreach my $key ( keys %hash ) {
$value = $hash{$key}
...
}
هنگامی که لیست کلیدها را دارید، می توانید قبل از پردازش هش، آن لیست را پردازش کنید
عناصر. به عنوان مثال، می توانید کلیدها را مرتب کنید تا بتوانید آنها را به ترتیب لغوی پردازش کنید:
foreach my $key ( کلیدهای مرتب سازی %hash ) {
$value = $hash{$key}
...
}
یا ممکن است بخواهید فقط برخی از موارد را پردازش کنید. اگر فقط می خواهید با
کلیدهایی که با "text:" شروع می شوند، می توانید فقط آنهایی را با استفاده از "grep" انتخاب کنید:
foreach my $key ( grep /^text:/, keys %hash ) {
$value = $hash{$key}
...
}
اگر هش بسیار بزرگ است، ممکن است نخواهید یک لیست طولانی از کلیدها ایجاد کنید. برای نجات برخی
حافظه، می توانید هر بار یک جفت کلید-مقدار را با استفاده از "each()" بگیرید که یک جفت شما را برمی گرداند.
هنوز ندیده ام:
while( my( $key, $value ) = every( %hash ) ) {
...
}
عملگر "هر" جفت ها را به ترتیب ظاهرا تصادفی برمی گرداند، بنابراین اگر سفارش مهم باشد
برای شما، باید از روش "کلیدها" استفاده کنید.
اگرچه عملگر "each()" ممکن است کمی مشکل باشد. شما نمی توانید کلیدهای هش را اضافه یا حذف کنید
در حالی که از آن استفاده می کنید بدون اینکه احتمالاً برخی از جفت ها را پس از پرل رد کنید یا دوباره پردازش کنید.
به صورت داخلی همه عناصر را دوباره بازخوانی می کند. علاوه بر این، یک هش تنها یک تکرار کننده دارد، بنابراین اگر
شما "کلیدها"، "مقدارها" یا "هر" را روی یک هش ترکیب می کنید، خطر بازنشانی تکرار کننده و
به هم ریختن پردازش شما برای جزئیات بیشتر به ورودی "هر" در perlfunc مراجعه کنید.
چگونه do I ادغام کردن دو هش؟
(با مشارکت برایان دی فوی)
قبل از اینکه تصمیم بگیرید دو هش را ادغام کنید، باید تصمیم بگیرید که اگر هر دو هش شوند، چه کاری انجام دهید
حاوی کلیدهایی است که یکسان هستند و اگر میخواهید هشهای اصلی را به همان شکلی که هستند رها کنید.
اگر میخواهید هشهای اصلی را حفظ کنید، یک هش (%hash1) را در یک هش جدید کپی کنید
(%new_hash)، سپس کلیدهای هش دیگر (%hash2) را به هش جدید اضافه کنید.
کلید از قبل در %new_hash وجود دارد به شما این فرصت را می دهد که تصمیم بگیرید با آن چه کاری انجام دهید
تکراری:
من %new_hash = %hash1; # یک کپی تهیه کنید. %hash1 را به حال خود رها کنید
foreach my $key2 ( کلیدهای %hash2 ) {
if( وجود $new_hash{$key2} ) {
هشدار "کلید [$key2] در هر دو هش است!";
# کنترل تکراری (شاید فقط هشدار)
...
بعد؛
}
دیگر {
$new_hash{$key2} = $hash2{$key2};
}
}
اگر نمیخواهید یک هش جدید ایجاد کنید، همچنان میتوانید از این تکنیک حلقهگذاری استفاده کنید. فقط
%new_hash را به %hash1 تغییر دهید.
foreach my $key2 ( کلیدهای %hash2 ) {
if( وجود $hash1{$key2} ) {
هشدار "کلید [$key2] در هر دو هش است!";
# کنترل تکراری (شاید فقط هشدار)
...
بعد؛
}
دیگر {
$hash1{$key2} = $hash2{$key2};
}
}
اگر اهمیتی نمی دهید که یک هش کلیدها و مقادیر را از دیگری بازنویسی می کند، فقط می توانید
از یک برش هش برای اضافه کردن یک هش به دیگری استفاده کنید. در این مورد، مقادیر %hash2 جایگزین می شوند
مقادیر از %hash1 وقتی کلیدهای مشترک داشته باشند:
@hash1{ کلیدهای %hash2 } = مقادیر %hash2;
چی اتفاق می افتد if I اضافه کردن or برداشتن کلید از جانب a مخلوط در حین در حال تکرار روی آن؟
(با مشارکت برایان دی فوی)
پاسخ آسان این است: "این کار را نکن!"
اگر از طریق هش با تکرار کنید هر یک()، می توانید کلیدی را که اخیراً بازگردانده شده است حذف کنید
بدون نگرانی در مورد آن اگر کلیدهای دیگر را حذف یا اضافه کنید، تکرارکننده ممکن است از یا رد شود
آنها را دوبرابر کنید زیرا پرل ممکن است جدول هش را دوباره مرتب کند. ورودی "each()" را در اینجا ببینید
perlfunc
چگونه do I نگاه up a مخلوط عنصر by مقدار؟
یک هش معکوس ایجاد کنید:
%by_value من = معکوس %by_key;
$key = $by_value{$value};
این کارایی خاصی ندارد. استفاده از آن در فضا کارآمدتر خواهد بود:
while (my ($key, $value) = هر %by_key) {
$by_value{$value} = $key;
}
اگر هش شما می تواند مقادیر تکراری داشته باشد، روش های بالا فقط یکی از آنها را پیدا می کنند
کلیدهای مرتبط این ممکن است شما را نگران کند یا نه. اگر شما را نگران می کند، همیشه می توانید
در عوض هش را به هش آرایه تبدیل کنید:
while (my ($key, $value) = هر %by_key) {
فشار @{$key_list_by_value{$value}}، $key;
}
چگونه می توان I دانستن چگونه بسیاری نوشته های هستند in a هش؟
(با مشارکت برایان دی فوی)
این بسیار شبیه به "چگونه کل هش را پردازش کنم؟" است، همچنین در perlfaq4، اما کمی
در موارد رایج ساده تر
می توانید از تابع داخلی "keys()" در زمینه اسکالر استفاده کنید تا متوجه شوید ورودی های زیادی دارید
شما در هش دارید:
$key_count = کلیدهای %hash; # باید زمینه اسکالر باشد!
اگر می خواهید بدانید که چه تعداد ورودی دارای یک مقدار تعریف شده هستند، کمی متفاوت است. شما
باید هر مقدار را بررسی کرد. یک "grep" مفید است:
$defined_value_count = grep { defined } مقادیر %hash;
می توانید از همان ساختار برای شمارش ورودی ها به هر شکلی که دوست دارید استفاده کنید. اگر بخواهید
تعداد کلیدهای دارای حروف صدادار در آنها، شما فقط آن را آزمایش کنید:
my $vowel_count = grep { /[aeiou]/ } کلیدهای %hash;
"grep" در زمینه اسکالر تعداد را برمی گرداند. اگر لیست موارد منطبق را می خواهید،
به جای آن فقط از آن در زمینه فهرست استفاده کنید:
my @defined_values = grep { defined } مقادیر %hash;
تابع "keys()" تکرار کننده را بازنشانی می کند، به این معنی که ممکن است عجیب و غریب ببینید
اگر از آن بین استفاده از سایر عملگرهای هش مانند "each()" استفاده کنید، نتیجه می شود.
چگونه do I نوع a مخلوط (اختیاری by ارزش در عوض of کلید)؟
(با مشارکت برایان دی فوی)
برای مرتب کردن هش، با کلیدها شروع کنید. در این مثال، ما لیستی از کلیدهای مرتب سازی را ارائه می دهیم
تابعی که سپس آنها را به صورت ASCII مقایسه می کند (که ممکن است تحت تأثیر منطقه شما قرار گیرد
تنظیمات). لیست خروجی دارای کلیدها به ترتیب ASCIIbetical است. وقتی کلیدها را در اختیار داریم، ما
می توانید از آنها عبور کنید تا گزارشی ایجاد کنید که کلیدها را به ترتیب ASCIIbetical فهرست می کند.
my @keys = مرتب سازی { $a cmp $b } کلیدها %hash;
foreach my $key ( @keys ) {
printf "%-20s %6d\n"، $key، $hash{$key}؛
}
اگرچه میتوانیم در بلوک "sort()" جذابتر باشیم. به جای مقایسه کلیدها، ما
می تواند یک مقدار را با آنها محاسبه کند و از آن مقدار به عنوان مقایسه استفاده کند.
به عنوان مثال، برای اینکه ترتیب گزارش خود را به حروف بزرگ و کوچک حساس کنیم، از "lc" برای کوچک کردن کلیدها استفاده می کنیم.
قبل از مقایسه آنها:
my @keys = sort { lc $a cmp lc $b } keys %hash;
توجه: اگر محاسبه گران است یا هش عناصر زیادی دارد، ممکن است بخواهید نگاه کنید
در Schwartzian Transform برای ذخیره نتایج محاسبات.
اگر بخواهیم بر اساس مقدار هش مرتب کنیم، از کلید هش برای جستجوی آن استفاده می کنیم. ما هنوز
لیستی از کلیدها را دریافت کنید، اما این بار آنها بر اساس ارزششان مرتب می شوند.
my @keys = مرتبسازی {$hash{$a} <=> $hash{$b} } کلیدها %hash;
از آنجا می توانیم پیچیده تر شویم. اگر مقادیر هش یکسان باشد، می توانیم a را ارائه کنیم
مرتب سازی ثانویه در کلید هش
کلیدهای @ من = مرتب کردن {
$hash{$a} <=> $hash{$b}
or
"\L$a" cmp "\L$b"
} کلید %hash;
چگونه می توان I همیشه نگه داشتن my مخلوط مرتب شده است؟
می توانید با استفاده از ماژول "DB_File" و "tie()" با استفاده از پیوندهای هش $DB_BTREE نگاه کنید.
همانطور که در "In Memory Databases" در DB_File مستند شده است. ماژول Tie::IxHash از CPAN ممکن است
همچنین آموزنده باشد اگرچه این هش شما را مرتب می کند، اما ممکن است از آن خوشتان نیاید
کاهش سرعت شما از رابط کراوات رنج می برند. آیا مطمئن هستید که باید این کار را انجام دهید؟ :)
چه خبر la تفاوت میان "حذف" و "undef" با هش؟
هش ها شامل جفت اسکالر هستند: اولی کلید، دومی مقدار است. کلید
به یک رشته اجباری می شود، اگرچه مقدار می تواند هر نوع اسکالر باشد: رشته، عدد،
یا مرجع اگر یک کلید $key در %hash وجود داشته باشد، "exists($hash{$key})" درست بر می گردد.
مقدار یک کلید داده شده می تواند "undef" باشد، در این صورت $hash{$key} "undef" خواهد بود در حالی که
"exists $hash{$key}" درست برمیگردد. این مربوط به ($key، "undef") بودن در
هش
تصاویر کمک می کنند... در اینجا جدول % hash آمده است:
مقادیر کلیدها
+------+------+
| یک | 3 |
| x | 7 |
| d | 0 |
| e | 2 |
+------+------+
و این شرایط برقرار است
$hash{'a'} درست است
$hash{'d'} نادرست است
$hash{'d'} تعریف شده درست است
تعریف شده $hash{'a'} درست است
موجود $hash{'a'} درست است (فقط Perl 5)
grep ($_ eq 'a'، کلیدهای %hash) درست است
اگر الان بگو
unef $hash{'a'}
جدول شما اکنون می گوید:
مقادیر کلیدها
+------+------+
| یک | undef|
| x | 7 |
| d | 0 |
| e | 2 |
+------+------+
و این شرایط اکنون برقرار است. تغییرات در کلاه:
$hash{'a'} FALSE است
$hash{'d'} نادرست است
$hash{'d'} تعریف شده درست است
$hash{'a'} تعریف شده FALSE است
موجود $hash{'a'} درست است (فقط Perl 5)
grep ($_ eq 'a'، کلیدهای %hash) درست است
به دو مورد آخر توجه کنید: شما یک مقدار undef دارید، اما یک کلید تعریف شده!
حالا این را در نظر بگیرید:
حذف $hash{'a'}
جدول شما اکنون می گوید:
مقادیر کلیدها
+------+------+
| x | 7 |
| d | 0 |
| e | 2 |
+------+------+
و این شرایط اکنون برقرار است. تغییرات در کلاه:
$hash{'a'} نادرست است
$hash{'d'} نادرست است
$hash{'d'} تعریف شده درست است
$hash{'a'} تعریف شده نادرست است
وجود دارد $hash{'a'} FALSE است (فقط Perl 5)
grep ($_ eq 'a'، keys %hash) FALSE است
ببینید، کل ورودی از بین رفته است!
چرا نکن my گره خورده است هش ساخت la تعریف شده/وجود دارد فرق - تمیز - تشخیص؟
این بستگی به اجرای هش گره خورده دارد وجود دارد(). به عنوان مثال، وجود ندارد
مفهوم undef با هش هایی که به فایل های DBM* گره خورده اند. همچنین به این معنی است وجود دارد() و
تعریف شده است() همین کار را با یک فایل DBM* انجام دهید، و کاری که در نهایت انجام میدهند کاری نیست که آنها انجام میدهند
با هش های معمولی انجام دهید.
چگونه do I تنظیم مجدد an هر یک() عمل نیمه راه از طریق؟
(با مشارکت برایان دی فوی)
می توانید از توابع "کلیدها" یا "مقدار" برای تنظیم مجدد "هر" استفاده کنید. برای اینکه به سادگی تکرار کننده را بازنشانی کنید
استفاده شده توسط "هر" بدون انجام کار دیگری، یکی از آنها را در زمینه خالی استفاده کنید:
کلیدهای %hash; # تکرارکننده را بازنشانی میکند، هیچ چیز دیگری.
مقادیر %hash; # تکرارکننده را بازنشانی میکند، هیچ چیز دیگری.
مستندات "هر" را در perlfunc ببینید.
چگونه می توان I دریافت کنید la منحصر به فرد کلید از جانب دو هش؟
ابتدا کلیدها را از هش ها به لیست ها استخراج می کنید، سپس "removing
مشکل تکراری" که در بالا توضیح داده شد. به عنوان مثال:
من %seen = ();
برای عنصر $ من (keys(%foo)، کلیدها(%bar)) {
$seen{$element}++;
}
my @uniq = کلیدهای %seen;
یا به طور خلاصه تر:
من @uniq = کلیدهای %{{%foo,%bar}};
یا اگر واقعاً می خواهید در فضا صرفه جویی کنید:
من %seen = ();
while (تعریف شده ($key = هر %foo)) {
$seen{$key}++;
}
while (تعریف شده ($key = هر %bar)) {
$seen{$key}++;
}
my @uniq = کلیدهای %seen;
چگونه می توان I opbevare a چند بعدی صف in a DBM فایل؟
یا خودتان ساختار را سختگیری کنید (بدون سرگرمی)، یا MLDBM را دریافت کنید (که از آن استفاده میکند
ماژول Data::Dumper) از CPAN و آن را در بالای DB_File یا GDBM_File قرار دهید. شما
ممکن است DBM::Deep را نیز امتحان کنید، اما ممکن است کمی کند باشد.
چگونه می توان I ساخت my مخلوط به یاد داشته باشید la سفارش I قرار دادن عناصر به آن؟
از Tie::IxHash از CPAN استفاده کنید.
استفاده از Tie::IxHash;
%myhash من را ببندید، 'Tie::IxHash';
برای ($i=0 من؛ $i<20؛ $i++) {
$myhash{$i} = 2*$i;
}
my @keys = کلیدهای %myhash;
# @keys = (0,1,2,3،XNUMX،XNUMX،XNUMX،...)
چرا میکند عبور a زیرروال an تعریف نشده عنصر in a مخلوط ایجاد آن؟
(با مشارکت برایان دی فوی)
آیا از نسخه واقعا قدیمی پرل استفاده می کنید؟
به طور معمول، دسترسی به مقدار یک کلید هش برای یک کلید وجود ندارد نه کلید را ایجاد کنید
من %hash = ();
my $value = $hash{ 'foo' };
چاپ "این چاپ نمی شود\n" در صورت وجود $hash{ 'foo' };
با این حال، ارسال $hash{ 'foo' } به یک زیر روال یک مورد خاص بود. از آنجایی که می توانستی
اختصاص مستقیم به $_[0]، Perl باید برای انجام آن تخصیص آماده می بود، بنابراین آن را ایجاد کرد
کلید هش زودتر از موعد:
my_sub( $hash{ 'foo' } );
چاپ "این قبل از 5.004\n چاپ خواهد شد" در صورت وجود $hash{ 'foo' };
زیر my_sub {
# $_[0] = 'نوار'; # در صورت انجام این کار، کلید هش ایجاد کنید
1;
}
اما از Perl 5.004، این وضعیت یک مورد خاص است و Perl کلید هش را ایجاد می کند
فقط زمانی که تکلیف را انجام می دهید:
my_sub( $hash{ 'foo' } );
چاپ "این چاپ خواهد شد، حتی بعد از 5.004\n" اگر وجود داشته باشد $hash{ 'foo' };
زیر my_sub {
$_[0] = 'نوار';
}
با این حال، اگر رفتار قدیمی را میخواهید (و با دقت در مورد آن فکر کنید زیرا عجیب است
عارضه جانبی)، میتوانید به جای آن یک برش هش ارسال کنید. Perl 5.004 این را خاص نکرده است
مورد:
my_sub( @hash{ qw/foo/ } );
چگونه می توان I ساخت la پرل معادل of a C ساختار/C++ کلاس/هش or صف of هش or
آرایه ها؟
معمولاً یک مرجع هش، شاید مانند این:
رکورد $ = {
NAME => "جیسون"،
EMPNO => 132،
TITLE => "معاون پیروان"،
سن => 23،
حقوق => 37_000،
PALS => [ "Norbert"، "Rhys"، "Phineas"]،
};
مراجع در perlref و perlreftut مستند شده اند. نمونه هایی از ساختارهای داده پیچیده
در perldsc و perllol داده می شود. نمونه هایی از ساختارها و کلاس های شی گرا هستند
در perlootut.
چگونه می توان I استفاده کنید a مرجع as a مخلوط کلید؟
(با مشارکت برایان دی فوی و بن مورو)
کلیدهای هش رشته هستند، بنابراین نمی توانید از یک مرجع به عنوان کلید استفاده کنید. وقتی سعی می کنید انجام دهید
که، پرل مرجع را به شکل رشته ای آن تبدیل می کند (به عنوان مثال،
"هاش(0xDEADBEEF)"). از آنجا نمیتوانید مرجع را از رشتهبندی شده برگردانید
حداقل بدون اینکه خودتان کار اضافی انجام دهید.
به یاد داشته باشید که ورودی در هش همچنان وجود دارد حتی اگر متغیر ارجاع شده باشد
از محدوده خارج می شود، و اینکه Perl کاملاً ممکن است متعاقباً a را اختصاص دهد
متغیرهای مختلف در یک آدرس این بدان معنی است که یک متغیر جدید ممکن است تصادفی باشد
با ارزش برای یک قدیمی مرتبط باشد.
اگر Perl 5.10 یا بالاتر دارید و فقط می خواهید مقداری را در برابر مرجع ذخیره کنید
برای جستجوی بعدی، می توانید از ماژول هسته Hash::Util::Fieldhash استفاده کنید. این نیز رسیدگی خواهد کرد
تغییر نام کلیدها در صورت استفاده از چندین رشته (که باعث می شود همه متغیرها باشند
تخصیص مجدد در آدرس های جدید، تغییر رشته آنها)، و جمع آوری زباله
زمانی وارد می شود که متغیر ارجاع شده از محدوده خارج شود.
اگر واقعاً نیاز دارید که بتوانید یک مرجع واقعی از هر ورودی هش دریافت کنید، می توانید
از ماژول Tie::RefHash استفاده کنید که کارهای مورد نیاز را برای شما انجام می دهد.
چگونه می توان I بررسی if a کلید وجود دارد in a چند سطحی هش؟
(با مشارکت برایان دی فوی)
ترفند این مشکل اجتناب از خودکارسازی تصادفی است. اگر می خواهید بررسی کنید
سه کلید عمیق، ممکن است ساده لوحانه این را امتحان کنید:
هش % من
if( وجود $hash{key1}{key2}{key3} ) {
...
}
حتی اگر با یک هش کاملاً خالی شروع کردید، پس از آن فراخوانی به "وجود" دارید
ساختار مورد نیاز برای بررسی "key3" را ایجاد کرد:
% هش = (
'key1' => {
'key2' => {}
}
);
این همان autovivification است. شما می توانید از چند طریق از این موضوع دور شوید. ساده ترین راه این است که فقط
خاموشش کن. پراگما واژگانی "autovivification" در CPAN موجود است. حالا شما اضافه نمی کنید
به هش:
{
بدون اتوویویفیکاسیون؛
هش % من
if( وجود $hash{key1}{key2}{key3} ) {
...
}
}
ماژول Data::Diver در CPAN می تواند این کار را برای شما نیز انجام دهد. زیرروال "Dive" آن می تواند به شما بگوید
نه تنها اگر کلیدها وجود داشته باشند، بلکه مقدار را نیز دریافت می کنند:
استفاده از Data::Diver qw(Dive);
my @exists = Dive( \%hash, qw(key1 key2 key3) );
if( ! @exists ) {
...; # کلید وجود ندارد
}
elif( ! defined $exists[0] ) {
...; # کلید وجود دارد اما مقدار آن unef است
}
شما به راحتی می توانید این کار را خودتان نیز با بررسی هر سطح از هش قبل از حرکت انجام دهید
به سطح بعدی این در اصل کاری است که Data::Diver برای شما انجام می دهد:
if( check_hash( \%hash, qw(key1 key2 key3) ) ) {
...
}
ساب check_hash {
my($hash، @keys) = @_;
بازگشت مگر اینکه @keys;
foreach my $key ( @keys ) {
بازگشت مگر اینکه eval { exists $hash->{$key} };
$hash = $hash->{$key};
}
1 بازگشت؛
}
چگونه می توان I جلوگیری از اضافه of ناخواسته کلید به a هش؟
از نسخه 5.8.0، هش می تواند باشد منحصر به تعداد ثابتی از کلیدهای داده شده روش هایی برای
ایجاد و برخورد با هش های محدود شده توسط ماژول Hash::Util صادر می شود.
داده ها: متفرقه
چگونه do I دسته دوتایی داده ها به درستی؟
پرل باینری تمیز است، بنابراین می تواند داده های باینری را به خوبی مدیریت کند. اما در ویندوز یا داس،
شما باید از "binmode" برای فایل های باینری استفاده کنید تا از تبدیل انتهای خطوط جلوگیری کنید. که در
به طور کلی، هر زمانی که می خواهید با داده های باینری کار کنید، باید از "binmode" استفاده کنید.
همچنین به "binmode" در perlfunc یا perlopentut مراجعه کنید.
اگر نگران داده های متنی 8 بیتی هستید، به perllocale مراجعه کنید. اگر می خواهید معامله کنید
با کاراکترهای چند بایتی، با این حال، برخی از مشکلات وجود دارد. به بخش Regular مراجعه کنید
اصطلاحات.
چگونه do I مشخص کردن چه a اسکالر is a عدد / کل / عدد صحیح / شناور؟
با فرض اینکه به نمادهای IEEE مانند "NaN" یا "Infinity" اهمیتی نمی دهید، احتمالاً
فقط می خواهم از یک عبارت منظم استفاده کنم:
استفاده از 5.010;
داده شده ($number ) {
وقتی (/\D/)
{ بگویید "\thas nondigits"; ادامه هید }
When(/^\d+\z/)
{بگویید "عدد کامل است"; ادامه هید }
When(/^-?\d+\z/)
{ بگویید "\tis یک عدد صحیح"; ادامه هید }
When(/^[+-]?\d+\z/ )
{ بگویید "\tis a +/- integer"; ادامه هید }
when( /^-?(?:\d+\.?|\.\d)\d*\z/)
{ بگویید "\tis a real number"; ادامه هید }
when(/^[+-]?(?=\.?\d)\d*\.?\d*(?:e[+-]?\d+)?\z/i)
{ بگویید "\tis a C float" }
}
همچنین برخی از ماژول های رایج برای این کار وجود دارد. Scalar::Util (توزیع شده با
5.8) دسترسی به تابع داخلی perl "looks_like_number" را برای تعیین فراهم می کند.
آیا یک متغیر شبیه یک عدد است. Data:: توابعی را صادر می کند که داده ها را تأیید می کند
با استفاده از عبارات بالا و سایر عبارات منظم، تایپ کنید. ثالثاً Regexp::Common وجود دارد
که دارای عبارات منظم برای مطابقت با انواع مختلف اعداد است. آن سه ماژول هستند
در دسترس از CPAN.
اگر از سیستم POSIX استفاده می کنید، Perl از تابع "POSIX::strtod" برای تبدیل پشتیبانی می کند.
رشته ها به دو برابر شدن (و همچنین "POSIX::strtol" برای طولانی). معنایی آن تا حدودی است
دست و پا گیر است، بنابراین برای دسترسی راحت تر، یک تابع پوشش "getnum" وجود دارد. این
تابع یک رشته می گیرد و عددی را که پیدا کرده است، یا "undef" را برای ورودی که a نیست برمی گرداند
سی شناور. تابع "is_numeric" یک قسمت جلویی برای "getnum" است اگر فقط بخواهید بگویید "Is
این یک شناور است؟"
sub getnum {
استفاده از POSIX qw(strtod)؛
my $str = shift;
$str =~ s/^\s+//;
$str =~ s/\s+$//;
$! = 0;
my($num, $unparsed) = strtod($str);
if (($str eq '') || ($unparsed != 0) || $!) {
بازگشت unef;
}
دیگر {
بازگشت $num;
}
}
زیر is_numeric { getnum تعریف شده ($_[0]) }
یا می توانید به جای آن ماژول String::Scanf را در CPAN بررسی کنید.
چگونه do I نگه داشتن ادامه داده ها در میان برنامه تماس می گیرد؟
برای برخی از برنامه های خاص، می توانید از یکی از ماژول های DBM استفاده کنید. AnyDBM_File را ببینید. بیشتر
به طور کلی، شما باید از ماژول های FreezeThaw یا Storable از CPAN مشورت کنید. راه افتادن
از Perl 5.8، Storable بخشی از توزیع استاندارد است. در اینجا یک مثال با استفاده از
توابع "ذخیره" و "بازیابی" Storable:
از Storable استفاده کنید.
store(\%hash، "نام فایل");
# بعد ها...
$href = retrieve("نام فایل"); # توسط رفر
%hash = %{ retrieve("filename") }; # مستقیم به هش
چگونه do I چاپ خارج or کپی کنید a بازگشتی داده ها ساختار؟
ماژول Data::Dumper در CPAN (یا نسخه 5.005 پرل) برای چاپ عالی است.
ساختارهای داده. ماژول Storable در CPAN (یا نسخه 5.8 پرل)، یک ارائه می دهد
تابعی به نام "dclone" که به صورت بازگشتی آرگومان خود را کپی می کند.
استفاده از Storable qw(dclone)؛
$r2 = dclone($r1);
جایی که $r1 می تواند مرجعی برای هر نوع ساختار داده ای باشد که شما می خواهید. عمیق خواهد بود
کپی شده از آنجا که "dclone" ارجاعات را می گیرد و برمی گرداند، باید علائم نگارشی اضافی اضافه کنید
اگر هش آرایههایی دارید که میخواهید کپی کنید.
%newhash = %{ dclone(\%oldhash) };
چگونه do I تعريف كردن روش برای هر کلاس / شی؟
(مشارکت توسط بن مورو)
می توانید از کلاس "UNIVERSAL" استفاده کنید (به UNIVERSAL مراجعه کنید). با این حال، لطفا بسیار مراقب باشید
عواقب انجام این کار را در نظر بگیرید: افزودن متدها به هر شی بسیار محتمل است
عواقب ناخواسته داشته باشد در صورت امکان، بهتر است تمام شیء خود را داشته باشید
از یک کلاس پایه مشترک به ارث برده شود یا از یک سیستم شی مانند Moose که پشتیبانی می کند استفاده کنید
نقش.
چگونه do I بررسی a اعتبار کارت چک جمع؟
ماژول Business::CreditCard را از CPAN دریافت کنید.
چگونه do I بسته آرایه ها of دو برابر میشود or شناور برای XS کد؟
کد arrays.h/arrays.c در ماژول PGPLOT در CPAN دقیقاً این کار را انجام می دهد. اگر در حال انجام یک
تعداد زیادی پردازش شناور یا دوگانه، به جای آن از ماژول PDL از CPAN استفاده کنید
اعداد را آسان می کند.
دیدنhttp://search.cpan.org/dist/PGPLOT> برای کد.
نویسنده و کپی رایت
حق چاپ (ج) 1997-2010 تام کریستینسن، ناتان تورکینگتون، و سایر نویسندگان همانطور که اشاره شد.
همه حقوق محفوظ است.
این مستندات رایگان است. شما می توانید آن را مجدداً توزیع کنید و/یا با همان شرایط تغییر دهید
به عنوان خود پرل.
صرف نظر از توزیع آن، تمام نمونه های کد موجود در این فایل در اینجا قرار می گیرند
حوزه عمومی شما مجاز و تشویق به استفاده از این کد در برنامه های خود هستید
برای سرگرمی یا برای سود به نظر شما. یک نظر ساده در کد اعتبار می دهد
مودب اما الزامی نیست
با استفاده از خدمات onworks.net از perlfaq4 به صورت آنلاین استفاده کنید