استخراج خطوط محددة (بناء على رقم السطر) باستخدام ملف دفعي
-
21-12-2019 - |
سؤال
أحتاج إلى استخراج أسطر محددة من ملف نصي (input.txt).لقد وجدت بالفعل حلاً ولكن لدي بعض التوضيحات لماذا لا يعمل عند استخدامه مع setlocalenabledealyed expansion
.أدناه هو المثال
لي input.txt (numbered using findstr /n)
.في هذا المثال، أحتاج إلى استخراج الخطوط الموجودة بين السطر رقم 27 إلى 39.في ملفي الدفعي الكامل، يتم استدعاء هذه القيم من وحدة نمطية أخرى.
1:[root]
2:ASKEHPPTEQWEIRAZOKXL
...
...
...
27:[parent2/child2]
28:NJ35CG5D9DEYXKMQKBJX
29:ZAZRMGB2E0KAG85FSPI3
30:E9046AQL44LV1R79OT8E
31:8OPXV1QYCTQVK34JZ2KV
32:3E32PWHGX5RGTFUXI9GC
33:H7DTDDFQZVGETGL764YU
34:174UOQMW35BCIQJNR1P8
35:7B3V0E9QXFQOM3NF08CZ
36:QH6FZVMKKGHKF0J8PB5O
37:QCRC90QCWWGAHRWBVMUI
38:4QPVEJW75GFW8DUM1PGU
39:[parent2/child3]
...
...
...
3000:[end]
الكود الأول - call.bat - استخدام CALL
@echo OFF
set st_ln=27
set end_ln=39
for /f "tokens=1,2 delims=:" %%a in (input.txt) do call :extract "%%a" "%%b"
goto :eof
:extract
set "ln=%~1"
set "sid=%~2"
if %ln% LEQ %st_ln% goto :eof
if %ln% GEQ %end_ln% goto :eof
echo.%sid%
goto :eof
:eof
الكود الثاني - local.bat يستعمل مع setlocalenabledelayedexpansion
REM @echo OFF
set st_ln=27
set end_ln=39
SETLOCAL ENABLEDELAYEDEXPANSION
for /f "tokens=1,2 delims=:" %%a in (input.txt) do (
set "ln=%%a"
set "sid=%%b"
if !ln! LEQ !st_ln! goto :eof
if !ln! GEQ !end_ln! goto :eof
echo.!sid!
)
:eof
انتاج - Calling.bat يعمل بشكل جيد تماما.لكن local.bat لا يُرجع أي خطأ، ولكنه يكرر حلقة for مرة واحدة فقط.(لقد حاولت استبدال !st_ln!& !end_ln!مع %st_ln% و%end_ln%، ولكن لا تزال نفس المشكلة) لماذا؟ماذا ينقصني؟
C:\Temp>calling.bat
NJ35CG5D9DEYXKMQKBJX
ZAZRMGB2E0KAG85FSPI3
E9046AQL44LV1R79OT8E
8OPXV1QYCTQVK34JZ2KV
3E32PWHGX5RGTFUXI9GC
H7DTDDFQZVGETGL764YU
174UOQMW35BCIQJNR1P8
7B3V0E9QXFQOM3NF08CZ
QH6FZVMKKGHKF0J8PB5O
QCRC90QCWWGAHRWBVMUI
4QPVEJW75GFW8DUM1PGU
C:\Temp>local.bat
C:\Temp>REM @echo OFF
C:\Temp>set st_ln=27
C:\Temp>set end_ln=39
C:\Temp>SETLOCAL ENABLEDELAYEDEXPANSION
C:\Temp>for /F "tokens=1,2 delims=:" %a in (input.txt) do (
set "ln=%a"
set "sid=%b"
if !ln! LEQ !st_ln! goto :eof
if !ln! GEQ !end_ln! goto :eof
echo.!sid!
)
C:\Temp>(
set "ln=1"
set "sid=[root]"
if !ln! LEQ !st_ln! goto :eof
if !ln! GEQ !end_ln! goto :eof
echo.!sid!
)
C:\Temp>
سؤال تكميلي:
كما قلت أعلاه، يمكنني الحصول على النتيجة المتوقعة، ولكن أريد فقط معرفة ما إذا كان من الممكن تحسينها.أريد استخراج أسطر محددة (يمكن أن تكون الأسطر في أي مكان في ملف الإدخال وقد يتراوح عدد الأسطر التي أحتاجها من 1 إلى 20)، من ملف الإدخال الذي يمكن أن يحتوي على ما يصل إلى 3000 سطر.أستخدم حاليًا في الكود أعلاه حلقة for وأتحقق من رقم السطر لكل سطر وبالتالي سيتم تكرارها خلال حلقة for لمدة 3000 مرة، مما قد يؤدي إلى تأخير الإخراج.هل هناك أي طريقة أخرى لتجنب ذلك وتسريع البرنامج النصي (قد يكون بحث findstr 'range')؟
المحلول
لك local.bat
لا يعمل لأنه عند قراءة السطر الأول، مع الرقم 1، والسطر البداية 27، الشرط if !ln! LEQ !st_ln! goto :eof
يتم تقييمه على أنه صحيح و goto
تم تنفيذ الأمر، وترك for
حلقة.
بالنسبة للسؤال التكميلي، يمكنك حساب عدد الصفوف التي يجب تخطيها في بداية الملف ثم المعالجة حتى الوصول إلى سطر النهاية فقط.نظرًا لعدم تغيير أي متغير داخل الحلقة، ليست هناك حاجة للتوسيع المتأخر
set /a "skipLines=st_ln-1"
if %skipLines% gtr 0 (
set "skipLines=skip=%skipLines%"
) else (
set "skipLines="
)
for /f "%skipLines% tokens=1,2 delims=:" %%a in (input.txt
) do if %%a gtr %end_ln% ( goto :eof ) else (
echo(%%b
)
ال if %skiplines% gtr 0
الاختبار ضروري كما for /f
الحلقة لا تسمح ب skip=0
بند