Mat M chính xác về giới hạn của FINDSTR. Hỗ trợ regex FINDSTR rất nguyên thủy và không chuẩn. Nhập HELP FINDSTR
hoặc FINDSTR /?
từ dòng lệnh để nhận tóm tắt ngắn gọn về những gì được hỗ trợ. Để được giải thích chi tiết, hãy tham khảo What are the undocumented features and limitations of the Windows FINDSTR command?
Tôi thích nhận xét của Harry Johnston - Sẽ khá dễ dàng khi tạo giải pháp bằng VBScript hoặc JavaScript. Tôi nghĩ đó sẽ là một lựa chọn tốt hơn nhiều.
Nhưng, đây là giải pháp theo lô gốc. Tôi đã kết hợp quy tắc bổ sung về số lượng các mẫu phụ mà OP đã nêu trong phần bình luận cho câu trả lời của Mat M.
Giải pháp là đáng ngạc nhiên phức tạp. Các ký tự đặc biệt có thể gây ra các vấn đề khi đường ống đầu ra ECHO đến FINDSTR vì đường ống hoạt động. Mỗi bên của đường ống được thực hiện trong phiên CMD riêng của nó. Các ký tự đặc biệt phải được trích dẫn, thoát hai lần hoặc chỉ được hiển thị thông qua việc mở rộng trễ. Tôi đã chọn sử dụng mở rộng chậm trễ, nhưng các ký tự !
phải được thoát hai lần để đảm bảo việc mở rộng trễ xảy ra vào đúng thời điểm.
Cách dễ nhất để phân tích cú pháp số lượng mẫu con thay đổi là thay thế dấu phân tách bằng một dòng mới và sử dụng FOR/F để lặp lại từng mẫu con.
Phần trên cùng của mã của tôi là một bộ mã hóa giòn để thuận tiện lặp lại và kiểm tra một bộ chuỗi. Nó sẽ không hoạt động đúng với bất kỳ <space>
;
,
=
<tab>
*
hoặc ?
trong chuỗi. Ngoài ra, các dấu ngoặc kép phải được cân bằng trong mỗi chuỗi.
Nhưng quy trình xác thực quan trọng hơn có thể xử lý bất kỳ chuỗi nào trong biến var.
@echo off
setlocal
set LF=^
::Above 2 blank lines are critical for creating a linefeed variable. Do not remove
set test=a
for %%S in (
"(3:"a"|"c"|"c")"
"(11:"a"|"b"|"c"|"d"|"esdf"|"f"|"g"|"h"|"i"|"j"|"k")"
"(4:"a"|"b"|"c")"
"(10:"a"|"b"|"c"|"d"|"esdf"|"f"|"g"|"h"|"i"|"j"|"k")"
"(3:"a"|"b"|"c""
"(3:"a"|"b^|c")"
"(3:"a"|"b"|c)"
"(3:"a"|"b"||"c")"
"(3:"a"|"b"|;|"c")"
) do (
set "var=%%~S"
call :validate
)
exit /b
:validate
setlocal enableDelayedExpansion
cmd /v:on /c echo ^^^!var^^^!|findstr /r /c:"^([1-9][0-9]*:.*)$" >nul || (call :invalid FINDSTR fail& exit /b)
if "!var:||=!" neq "!var!" (call :invalid double pipe fail& exit /b)
for /f "delims=(:" %%N in ("!var!") do set "expectedCount=%%N"
set "str=!var:*:=!"
set "str=!str:~0,-1!"
set foundCount=0
for %%A in ("!LF!") do for /f eol^=^%LF%%LF%^ delims^= %%B in ("!str:|=%%~A!") do (
if %%B neq "%%~B" (call :invalid sub-pattern fail& exit /b)
set /a foundCount+=1
)
if %foundCount% neq %expectedCount% (call :invalid count fail& exit /b)
echo Valid: !var!
exit /b
:invalid
echo Invalid - %*: !var!
exit /b
Đây là kết quả sau khi chạy các tập lệnh batch
Valid: (3:"a"|"c"|"c")
Valid: (11:"a"|"b"|"c"|"d"|"esdf"|"f"|"g"|"h"|"i"|"j"|"k")
Invalid - count fail: (4:"a"|"b"|"c")
Invalid - count fail: (10:"a"|"b"|"c"|"d"|"esdf"|"f"|"g"|"h"|"i"|"j"|"k")
Invalid - FINDSTR fail: (3:"a"|"b"|"c"
Invalid - sub-pattern fail: (3:"a"|"b|c")
Invalid - sub-pattern fail: (3:"a"|"b"|c)
Invalid - double pipe fail: (3:"a"|"b"||"c")
Invalid - sub-pattern fail: (3:"a"|"b"|;|"c")
Cập nhật
Những thói quen :validate
có thể được đơn giản hóa một chút bằng cách trì hoãn các enablement mở rộng trì hoãn cho đến sau khi CMD /V:ON
ống. Điều này có nghĩa là tôi không còn phải lo lắng về việc thoát kép hai lần !
ở phía bên trái của đường ống.
:validate
cmd /v:on /c echo !var!|findstr /r /c:"^([1-9][0-9]*:.*)$" >nul || (call :invalid FINDSTR fail& exit /b)
setlocal enableDelayedExpansion
... remainder unchanged
Nếu có thể, bạn có thể nên sử dụng VBScript hoặc PowerShell. Thao tác các chuỗi chứa các ký tự đặc biệt là vô cùng khó khăn trong các tệp lô Windows. –
@Harry Johnston Thật không may tôi không thể sử dụng bất cứ điều gì khác hơn là lệnh nội bộ hoặc bên ngoài tiêu chuẩn để cmd.exe. – networkcode
VBScript và JScript là các tiện ích bản địa chuẩn có sẵn cho CMD.EXE, với hỗ trợ regex tốt. PowerShell có nguồn gốc từ Vista trở đi, và cũng có hỗ trợ regex tốt. – dbenham