@@ -396,6 +396,8 @@ contains |
| 396 | 396 | work_head = work_head + 1 |
| 397 | 397 | |
| 398 | 398 | ! Compute transitions for all 256 characters |
| 399 | + ! For case-insensitive matching, we compute transitions for both cases |
| 400 | + ! and union them so 'a' and 'A' go to the same DFA state |
| 399 | 401 | do char_code = 0, 255 |
| 400 | 402 | call next_set%clear() |
| 401 | 403 | |
@@ -403,6 +405,17 @@ contains |
| 403 | 405 | call compute_char_transitions_simple(opt%nfa, opt%dfa%states(dfa_idx)%nfa_states, & |
| 404 | 406 | char(char_code), next_set) |
| 405 | 407 | |
| 408 | + ! For alphabetic characters, also compute transitions for opposite case |
| 409 | + if (char_code >= ichar('a') .and. char_code <= ichar('z')) then |
| 410 | + ! Also try uppercase |
| 411 | + call compute_char_transitions_simple(opt%nfa, opt%dfa%states(dfa_idx)%nfa_states, & |
| 412 | + char(char_code - 32), next_set) |
| 413 | + else if (char_code >= ichar('A') .and. char_code <= ichar('Z')) then |
| 414 | + ! Also try lowercase |
| 415 | + call compute_char_transitions_simple(opt%nfa, opt%dfa%states(dfa_idx)%nfa_states, & |
| 416 | + char(char_code + 32), next_set) |
| 417 | + end if |
| 418 | + |
| 406 | 419 | ! Compute epsilon closure of result |
| 407 | 420 | if (.not. next_set%is_empty()) then |
| 408 | 421 | call expand_epsilon_closure_simple(opt%nfa, next_set) |
@@ -574,8 +587,8 @@ contains |
| 574 | 587 | if (opt%nfa%num_states == 0) return |
| 575 | 588 | |
| 576 | 589 | ! Fast path: use DFA if available (O(n) matching) |
| 577 | | - ! DFA only works for case-sensitive matching (case-insensitive would need 2x states) |
| 578 | | - if (opt%use_dfa .and. .not. ignore_case) then |
| 590 | + ! DFA now supports case-insensitive matching via case-folded transitions |
| 591 | + if (opt%use_dfa) then |
| 579 | 592 | res = dfa_search(opt%dfa, text, text_len) |
| 580 | 593 | return |
| 581 | 594 | end if |