.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.45) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Required to disable full justification in groff 1.23.0. .if n .ds AD l .\" ======================================================================== .\" .IX Title "BT_POST_PROCESSING 1" .TH BT_POST_PROCESSING 1 2025-07-14 "btparse, version 0.91" btparse .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "نام (NAME)" bt_post_processing \- پس‌پردازش رشته‌ها، مقادیر و مدخل‌های BibTeX .SH "خلاصه دستور (SYNOPSIS)" .IX Header "SYNOPSIS" .Vb 2 \& void bt_postprocess_string (char * s, \& btshort options) \& \& char * bt_postprocess_value (AST * value, \& btshort options, \& boolean replace); \& \& char * bt_postprocess_field (AST * field, \& btshort options, \& boolean replace); \& \& void bt_postprocess_entry (AST * entry, \& btshort options); .Ve .SH "توضیحات (DESCRIPTION)" .IX Header "DESCRIPTION" هنگامی که \fBbtparse\fR یک مدخل BibTeX را تجزیه می‌کند، نتایج را در ابتدا در یک درخت نحو انتزاعی (AST)، به شکلی که دقیقاً بازتاب‌دهندهٔ داده‌های تجزیه‌شده است، ذخیره می‌نماید. برای مثال، مدخل .PP .Vb 7 \& @Article{Jones:1997a, \& AuThOr = "Bob Jones" # and # "Jim Smith ", \& TITLE = "Feeding Habits of \& the Common Cockroach", \& JoUrNaL = j_ent, \& YEAR = 1997 \& } .Ve .PP به یک AST تجزیه می‌شود که می‌تواند به صورت زیر نمایش داده شود: .PP .Vb 12 \& (entry,"Article") \& (key,"Jones:1997a") \& (field,"AuThOr") \& (string,"Bob Jones") \& (macro,"and") \& (string,"Jim Smith ") \& (field,"TITLE") \& (string,"Feeding Habits of the Common Cockroach") \& (field,"JoUrNaL") \& (macro,"j_ent") \& (field,"YEAR") \& (number,"1997") .Ve .PP مزیت این قالب در این است که تمامی اطلاعات مهم مدخل با پیمایش درخت با استفاده از توابع شرح داده شده در bt_traversal به‌آسانی در دسترس هستند. اما مشکل آشکار این است که داده‌ها بیش از حد خام هستند و نمی‌توان بلافاصله از آن‌ها استفاده کرد: حروف بزرگ و کوچک در انواع مدخل‌ها و نام‌های فیلدها ناهماهنگ است، رشته‌ها پر از فاصله‌های خالی ناخواسته هستند، مقادیر فیلدها به یک رشتهٔ واحد تقلیل نیافته‌اند، و مواردی از این دست. .PP تمام این مشکلات توسط توابع پس‌پردازش \fBbtparse\fR که در اینجا توضیح داده شده‌اند، برطرف می‌شوند. به‌طور معمول، نیازی به فراخوانی این توابع نخواهید داشت\-\-\-کتابخانه پس از تجزیهٔ هر مدخل «کار درست» را برای شما انجام می‌دهد، و شما می‌توانید مشخص کنید که دقیقاً چه چیزی برای برنامهٔ شما «کار درست» است. (برای نمونه، می‌توانید به آن بگویید ماکروها را بسط دهد، اما زیررشته‌ها را به یکدیگر الحاق نکند.) با این حال، ممکن است بخواهید پس‌پردازش را به کد خود و خارج از کنترل کتابخانه منتقل کنید. محتمل‌تر این است که رشته‌هایی از جایی غیر از فایل‌های BibTeX داشته باشید و بخواهید با آن‌ها مانند رشته‌های BibTeX رفتار شود؛ در این شرایط، توابع پس‌پردازش ضروری هستند. در نهایت، ممکن است صرفاً کنجکاو باشید که پس از تجزیهٔ داده‌هایتان، دقیقاً چه بر سر آن‌ها می‌آید. اگر چنین است، برای دریافت توضیحاتی بسیار موشکافانه و دقیق به جای درستی آمده‌اید. .SH "توابع (FUNCTIONS)" .IX Header "FUNCTIONS" \&\fBbtparse\fR چهار نقطهٔ ورود برای کد پس‌پردازش خود فراهم می‌کند. از میان این‌ها، احتمالاً تنها مورد اول و آخر\-\-\-برای پردازش رشته‌های منفرد و کل مدخل‌ها\-\-\-کاربرد متداول خواهند داشت. .SS "نقاط ورود پس‌پردازش (Post\-processing entry points)" .IX Subsection "Post-processing entry points" برای درک چرایی ارائهٔ چهار نقطهٔ ورود، توضیحی دربارهٔ نمونه AST ارائه‌شده در بالا کمک‌کننده خواهد بود. پیش از هر چیز، کل مدخل توسط گره \f(CW\*(C`(entry,"Article")\*(C'\fR نمایش داده می‌شود؛ این گره کلید مدخل و تمام جفت‌های فیلد/مقدار آن را به عنوان فرزندان خود دارد. گره‌های مدخل توسط \f(CWbt_parse_entry()\fR و \f(CWbt_parse_entry_s()\fR (نگاه کنید به bt_input) و همچنین \f(CWbt_next_entry()\fR (که فهرستی از مدخل‌های بازگردانده شده از \f(CWbt_parse_file()\fR را پیمایش می‌کند\-\-\-نگاه کنید به bt_traversal) برگردانده می‌شوند. کل مدخل‌ها را می‌توان با \f(CWbt_postprocess_entry()\fR پس‌پردازش کرد. .PP همچنین ممکن است نیاز به پس‌پردازش یک فیلد منفرد، یا صرفاً مقدار مرتبط با آن داشته باشید. (تفاوت در این است که پردازش فیلد علاوه بر مقدار فیلد، می‌تواند نام فیلد را نیز\-\-\-برای مثال به حروف کوچک\-\-\-تغییر دهد.) گره \f(CW\*(C`(field,"AuThOr")\*(C'\fR در بالا نمونه‌ای از یک زیر\-AST فیلد است، و \f(CW\*(C`(string,"Bob Jones")\*(C'\fR نخستین گره در فهرست مقادیر ساده است که مقدار آن فیلد را نمایش می‌دهد. (به یاد داشته باشید که مقدار یک فیلد، به‌طور کلی، فهرستی از مقادیر ساده است.) گره‌های فیلد توسط \f(CWbt_next_field()\fR و گره‌های مقدار توسط \f(CWbt_next_value()\fR برگردانده می‌شوند. مورد اول را می‌توان برای پس‌پردازش به \f(CWbt_postprocess_field()\fR و مورد دوم را به \f(CWbt_postprocess_value()\fR ارسال کرد. .PP در نهایت، رشته‌های منفرد ممکن است از جاهای متعددی غیر از یک AST در \fBbtparse\fR وارد برنامهٔ شما شوند. به همین دلیل، \f(CWbt_postprocess_string()\fR برای پس‌پردازش رشته‌های دلخواه در دسترس است. .SS "گزینه‌های پس‌پردازش (Post\-processing options)" .IX Subsection "Post-processing options" تمام توابع پس‌پردازش دارای پارامتر \f(CW\*(C`options\*(C'\fR هستند که می‌توانید از آن برای تنظیم دقیق پس‌پردازش استفاده کنید. (این دقیقاً مانند گزینه‌های پردازش رشته به ازای هر متاتایپ است که می‌توانید پیش از تجزیهٔ مدخل‌ها تنظیم کنید؛ نگاه کنید به \f(CWbt_set_stringopts()\fR در bt_input.) مانند جاهای دیگر کتابخانه، \f(CW\*(C`options\*(C'\fR یک نگاشت بیتی (bitmap) است که از OR کردن ثوابت مختلف از پیش تعریف‌شده با یکدیگر ساخته می‌شود. این ثوابت و تأثیرات آن‌ها در بخش "String processing option macros" در btparse مستند شده‌اند. .IP "bt_postprocess_string ()" 4 .IX Item "bt_postprocess_string ()" .Vb 2 \& void bt_postprocess_string (char * s, \& btshort options) .Ve .Sp یک رشتهٔ منفرد، \f(CW\*(C`s\*(C'\fR را درجا تغییر داده و پس‌پردازش می‌کند. تنها گزینهٔ پس‌پردازش که برای رشته‌های منفرد معنی دارد، فشرده‌سازی فاصله‌های خالی طبق قوانین BibTeX است؛ بنابراین، اگر \f(CW\*(C`options & BTO_COLLAPSE\*(C'\fR نادرست (false) باشد، این تابع اثری نخواهد داشت. (اگرچه در هر صورت یک دور کامل روی رشته پیمایش می‌کند؛ این امر برای توسعه در آینده است.) .Sp قوانین دقیق فشرده‌سازی فاصله‌های خالی ساده هستند: نویسه‌های فاصلهٔ خالی غیر از space (عمدتاً تب‌ها و خطوط جدید) به space تبدیل می‌شوند، هر توالی بیش از یک space در میان متن به یک space واحد فشرده می‌شود، و تمام فاصله‌های آغازین یا پایانی حذف می‌گردند. (اطمینان از اینکه تمامی فاصله‌های خالی نویسهٔ space باشند در واقع توسط پویشگر واژگانی \fBbtparse\fR انجام می‌شود، بنابراین رشته‌ها در ASTهای \fBbtparse\fR هرگز فاصله‌ای جز space نخواهند داشت. به همین ترتیب، هر رشته‌ای که به \fBbt_postprocess_string()\fR ارسال می‌شود نباید شامل نویسه‌های فاصلهٔ خالی غیر از space باشد.) .IP "bt_postprocess_value ()" 4 .IX Item "bt_postprocess_value ()" .Vb 3 \& char * bt_postprocess_value (AST * value, \& btshort options, \& boolean replace); .Ve .Sp یک مقدار فیلد منفرد را پس‌پردازش می‌کند که سرِ فهرستی از مقادیر سادهٔ بازگردانده شده توسط \f(CWbt_next_value()\fR است. تمامی گزینه‌های مرتبط با پردازش رشته در اینجا وارد عمل می‌شوند: تبدیل اعداد به رشته‌ها (\f(CW\*(C`BTO_CONVERT\*(C'\fR)، بسط ماکروها (\f(CW\*(C`BTO_EXPAND\*(C'\fR)، فشرده‌سازی فاصله‌های خالی (\f(CW\*(C`BTO_COLLAPSE\*(C'\fR)، و چسباندن رشته‌ها (\f(CW\*(C`BTO_PASTE\*(C'\fR). از آنجا که چسباندن زیررشته‌ها به یکدیگر بدون بسط اولیهٔ ماکروها و تبدیل اعداد بی‌معنی است، تلاش برای انجام این کار یک خطای مهلک است. .Sp اگر \f(CW\*(C`replace\*(C'\fR درست (true) باشد، فهرستی که \f(CW\*(C`value\*(C'\fR در رأس آن است با فهرستی جایگزین می‌شود که مقدار پردازش‌شده را نشان می‌دهد. بدین معنا که اگر چسباندن رشته فعال باشد (\f(CW\*(C`options & BTO_PASTE\*(C'\fR درست باشد)، این فهرست به یک گرهٔ واحد فشرده خواهد شد که حاوی رشتهٔ منفرد حاصل از چسباندن تمام زیررشته‌ها است. اگر چسباندن رشته فعال نباشد، هر گره در فهرست دست‌نخورده باقی می‌ماند، اما متن آن با متن پردازش‌شده جایگزین می‌شود. .Sp اگر \f(CW\*(C`replace\*(C'\fR نادرست (false) باشد، یک رشتهٔ جدید در لحظه ساخته شده و توسط تابع بازگردانده می‌شود. توجه داشته باشید که اگر چسباندن در این حالت فعال نباشد، شما فقط آخرین رشته در فهرست را دریافت خواهید کرد. (هرچند پس‌پردازش یک مقدار بدون چسباندن چندان معقول نیست، مگر اینکه بخواهید آن را با مقدار جدید جایگزین کنید.) .Sp رشتهٔ حاصل از پردازش کل مقدار را بازمی‌گرداند؛ این بازگشت تنها در حالتی معنادار است که چسباندن فعال بوده باشد یا فقط یک مقدار در فهرست وجود داشته باشد. اگر یک فهرست چندمقداری بدون چسباندن پردازش شود، آخرین رشته در فهرست (پس از پردازش) بازگردانده می‌شود. .Sp بررسی کنید که چه کاری می‌توان روی مقدار فیلد \f(CW\*(C`author\*(C'\fR در مثال بالا انجام داد، که الحاقی از یک رشته، یک ماکرو و یک رشتهٔ دیگر است. فرض کنید که ماکروی \f(CW\*(C`and\*(C'\fR به \f(CW" and "\fR بسط می‌یابد، و متغیر \f(CW\*(C`value\*(C'\fR به زیر\-AST این مقدار اشاره می‌کند. زیر\-AST اصلی متناظر با این مقدار به این صورت است: .Sp .Vb 3 \& (string,"Bob Jones") \& (macro,"and") \& (string,"Jim Smith ") .Ve .Sp برای پردازش کامل این مقدار درجا (in-place)، دستور زیر را فراخوانی می‌کنید: .Sp .Vb 1 \& bt_postprocess_value (value, BTO_FULL, TRUE); .Ve .Sp (\f(CW\*(C`BTO_FULL\*(C'\fR صرفاً ترکیبی از تمام گزینه‌های ممکن پردازش رشته است: \f(CW\*(C`BTO_CONVERT|BTO_EXPAND|BTO_PASTE|BTO_COLLAPSE\*(C'\fR.) این کار مقدار را به یک فهرست تک‌عنصری تبدیل می‌کند: .Sp .Vb 1 \& (string,"Bob Jones and Jim Smith") .Ve .Sp و رشتهٔ کاملاً پردازش‌شدهٔ \f(CW"Bob Jones and Jim Smith"\fR را بازمی‌گرداند. توجه داشته باشید که ماکروی \f(CW\*(C`and\*(C'\fR بسط یافته، میان دو رشتهٔ لفظی قرار گرفته، همه‌چیز به یکدیگر چسبانده شده، و در نهایت فاصله‌های خالی فشرده شده‌اند. (فشرده‌سازی فاصله‌های خالی پیش از الحاق رشته‌ها ایدهٔ بدی خواهد بود.) .Sp فرض کنید ترجیح می‌دهید ماهیت فهرستی مقدار را حفظ کنید، در حالی که ماکروها بسط داده شده و هر عددی به رشته تبدیل شود. (این تبدیل ناچیز است: صرفاً نوع گره را از \f(CW\*(C`BTAST_NUMBER\*(C'\fR به \f(CW\*(C`BTAST_STRING\*(C'\fR تغییر می‌دهد. مقادیر «عددی» همواره به صورت رشته‌ای از ارقام ذخیره می‌شوند، درست همان‌طور که در فایل ظاهر می‌گردند.) این کار با فراخوانی زیر انجام می‌شود: .Sp .Vb 2 \& bt_postprocess_value \& (value, BTO_CONVERT|BTO_EXPAND|BTO_COLLAPSE,TRUE); .Ve .Sp که فهرست را به این صورت تغییر می‌دهد: .Sp .Vb 3 \& (string,"Bob Jones") \& (string,"and") \& (string,"Jim Smith") .Ve .Sp توجه داشته باشید که فاصله‌های خالی در اینجا \fIپیش از\fR امکان انجام هرگونه الحاق فشرده شده‌اند؛ این کار احتمالاً ایدهٔ بدی است. اما اگر بخواهید می‌توانید انجامش دهید. (اگر فکری به سرتان زده که با انجام گام‌های کوچک این‌چنینی روش پس‌پردازش مقدار مخصوص به خود را سرهم کنید، نگاهی به کد منبع \f(CWbt_postprocess_value()\fR بیندازید؛ این کار باید شما را از چنین مخاطره‌ای منصرف کند.) .IP "bt_postprocess_field ()" 4 .IX Item "bt_postprocess_field ()" .Vb 3 \& char * bt_postprocess_field (AST * field, \& btshort options, \& boolean replace); .Ve .Sp این تابع اساساً چیزی بیش از یک پیشانه (front-end) برای \f(CWbt_postprocess_value()\fR نیست؛ تنها تفاوت این است که یک گره AST از نوع «field» به آن ارسال می‌کنید (مانند \f(CW\*(C`(field,"AuThOr")\*(C'\fR در مثال بالا)، و اینکه این تابع علاوه بر مقدار فیلد، نام فیلد را نیز دگرگون می‌کند. به ویژه، نام فیلد به اجبار به حروف کوچک تبدیل می‌شود؛ این رفتار (در حال حاضر) اختیاری نیست. .Sp رشتهٔ بازگردانده شده توسط \f(CWbt_postprocess_value()\fR را برمی‌گرداند. .IP "bt_postprocess_entry ()" 4 .IX Item "bt_postprocess_entry ()" .Vb 2 \& void bt_postprocess_entry (AST * entry, \& btshort options); .Ve .Sp تمام مقادیر موجود در یک مدخل را پس‌پردازش می‌کند. اگر \f(CW\*(C`entry\*(C'\fR به AST یک مدخل «عادی» یا «تعریف ماکرو» اشاره کند، مقادیر دقیقاً همان چیزی هستند که انتظار دارید: هر آنچه در سمت راست «انتساب» یک فیلد یا ماکرو قرار دارد. با این حال، می‌توانید مدخل‌های comment و preamble را نیز پس‌پردازش کنید. مدخل‌های توضیح (comment) اساساً یک رشتهٔ بزرگ هستند، بنابراین تنها فشرده‌سازی فاصله‌های خالی برای آن‌ها معنا دارد. مدخل‌های preamble ممکن است چندین رشتهٔ چسبانده‌شده به یکدیگر داشته باشند، بنابراین تمام گزینه‌های پردازش رشته برای آن‌ها اعمال‌پذیر است. (و هیچ‌چیز مانع استفاده از ماکروها در یک preamble نمی‌شود.)