2012-09-23 31 views
5

Tôi phải kiểm tra tính hợp lệ của chuỗi được lưu trữ trong một biến, tôi không thể sử dụng các tiện ích CLI bên ngoài (grep, awk, v.v.) vì vậy tôi đã chọn FINDSTR. Chuỗi có định dạng này (trong regexp):Sử dụng các mẫu con trong FINDSTR

([1-9][0-9]*:".*"(|".*")*) 

Tôi không biết làm thế nào để kiểm tra subpattern (| "*".). Hiện tại, mã của tôi là:

((ECHO.) | (SET /P "=(11:"a"|"b"|"c")") | (FINDSTR /R /C:"^([1-9][0-9]*:".*")$")) 

Kính trọng.

+2

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. –

+0

@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

+1

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

Trả lời

6

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 
+0

Tốt, mặc dù chúng tôi không biết liệu trường hợp thử nghiệm thứ 6 có thực sự sai hay không. –

+0

@MatM - điểm tốt. Nếu nó hợp lệ thì giải pháp sẽ phức tạp hơn nhiều. – dbenham

+0

@ dbenham: giải pháp là chính xác, cảm ơn bạn! Tôi muốn nói với bạn về một dự án tôi đã làm theo lô để có ý kiến ​​của bạn, có thể là mối quan tâm chung! – networkcode

2

Theo như tôi biết, findstr không thể nhóm regexps, vì vậy (|".*")* là không có. Nếu bạn biết có bao nhiêu khối bạn có và bạn lặp lại code của bạn như thế này

FINDSTR /R /C:"^([1-9][0-9]*:\"..*\"|\"..*\"|\"..*\")$" 

Bằng cách này, nếu bạn chắc chắn số khối là hằng số, có những sản phẩm nào "" nếu có yêu cầu, sau đó bạn có thể kiểm tra nó.

Dấu ngoặc kép bên trong biểu thức được bỏ qua trừ khi bạn đặt tiền tố cho chúng bằng \.
Cấu trúc ..* có nghĩa là thay thế .+: một hoặc nhiều ký tự.

+0

Chuỗi không thể chứa số lượng mẫu con không thay đổi, số biến được truyền từ số đầu tiên, sau đó là:. Có lẽ một giải pháp sẽ được xác nhận ngay lập tức chuỗi với một FINDSTR và sau đó phân tích mã thông báo cho mỗi mẫu con với FOR/F, nếu chính xác về nội dung và số, bạn nghĩ sao? – networkcode

+0

@ user1125183 - Điều đó sẽ hiệu quả nhưng rất khó. Xem [câu trả lời của tôi] (http://stackoverflow.com/a/12570555/1012053) – dbenham

Các vấn đề liên quan