2010-03-28 37 views
6

Tôi muốn để có thể phân tích cú pháp đường dẫn tập tin như thế này một:Regular Expression để phù hợp với số lượng không giới hạn các lựa chọn

/var/www/index.(htm|html|php|shtml) 

vào một mảng ra lệnh:

array("htm", "html", "php", "shtml") 

và sau đó tạo ra một danh sách các lựa chọn thay thế :

/var/www/index.htm 
/var/www/index.html 
/var/www/index.php 
/var/www/index.shtml 

Hiện tại, tôi có tuyên bố preg_match có thể chia tách hai lựa chọn:

preg_match_all ("/\(([^)]*)\|([^)]*)\)/", $path_resource, $matches); 

ai đó có thể cho tôi một con trỏ cách mở rộng này để chấp nhận một không giới hạn số lựa chọn thay thế (ít nhất là hai)? Chỉ liên quan đến biểu thức chính quy, phần còn lại tôi có thể giải quyết.

Quy tắc là:

  • Danh sách này cần phải bắt đầu với một ( và gần gũi với một )

  • Phải có một | trong danh sách (tức là ít nhất hai lựa chọn thay thế)

  • Bất kỳ lần xuất hiện nào khác của ( hoặc ) vẫn không bị ảnh hưởng.

Cập nhật: tôi cần để có thể cũng phải đối phó với nhiều cặp khung như:

/var/(www|www2)/index.(htm|html|php|shtml) 

xin lỗi tôi không nói rằng ngay lập tức.

Cập nhật 2: Nếu bạn đang tìm kiếm để làm những gì tôi đang cố gắng để làm trong hệ thống tập tin, sau đó lưu ý rằng glob() đã mang lại chức năng này ra khỏi hộp. Không cần phải thực hiện một solutiom tùy chỉnh. Xem câu trả lời của @ Gordon bên dưới để biết chi tiết.

+1

Tại sao các địa ngục là tất cả mọi người * * bị ám ảnh ** với regex? Chỉ cần sử dụng một phương pháp damn khác. Kết hợp mọi thứ sau một khung là ** không khó ** nếu không có regex. –

+0

@Coronatus chỉ cho tôi một phương thức không regex trọng lượng nhẹ, thanh lịch có thể xử lý nhiều cặp dấu ngoặc và 2. bỏ qua bất kỳ cặp khung nào không chứa '|', và trông không giống như shit, và tôi ' ll sẵn sàng vẽ mũ của tôi cho bạn. –

+1

Xong. Xem câu trả lời của tôi. –

Trả lời

3

giải pháp Non-regex :)

<?php 

$test = '/var/www/index.(htm|html|php|shtml)'; 

/** 
* 
* @param string $str "/var/www/index.(htm|html|php|shtml)" 
* @return array "/var/www/index.htm", "/var/www/index.php", etc 
*/ 
function expand_bracket_pair($str) 
{ 
    // Only get the very last "(" and ignore all others. 
    $bracketStartPos = strrpos($str, '('); 
    $bracketEndPos = strrpos($str, ')'); 

    // Split on ",". 
    $exts = substr($str, $bracketStartPos, $bracketEndPos - $bracketStartPos); 
    $exts = trim($exts, '()|'); 
    $exts = explode('|', $exts); 

    // List all possible file names. 
    $names = array(); 

    $prefix = substr($str, 0, $bracketStartPos); 
    $affix = substr($str, $bracketEndPos + 1); 
    foreach ($exts as $ext) 
    { 
     $names[] = "{$prefix}{$ext}{$affix}"; 
    } 

    return $names; 
} 

function expand_filenames($input) 
{ 
    $nbBrackets = substr_count($input, '('); 

    // Start with the last pair. 
    $sets = expand_bracket_pair($input); 

    // Now work backwards and recurse for each generated filename set. 
    for ($i = 0; $i < $nbBrackets; $i++) 
    { 
     foreach ($sets as $k => $set) 
     { 
      $sets = array_merge(
       $sets, 
       expand_bracket_pair($set) 
      ); 
     } 
    } 

    // Clean up. 
    foreach ($sets as $k => $set) 
    { 
     if (false !== strpos($set, '(')) 
     { 
      unset($sets[$k]); 
     } 
    } 
    $sets = array_unique($sets); 
    sort($sets); 

    return $sets; 
} 

var_dump(expand_filenames('/(a|b)/var/(www|www2)/index.(htm|html|php|shtml)')); 
+0

Công việc rất hay - Kudos cho bạn. * Nhưng * nó không thể đối phó với nhiều cặp khung như tôi đã làm * không * đề cập đến trong câu hỏi của tôi - tôi sẽ sửa chữa ngay lập tức - nhưng * đã * trong thử thách của tôi với bạn. :) Tôi nghĩ rằng phương pháp này khó mở rộng để nó có thể đối phó với nhiều cặp khung. Hay tôi nhầm? –

+0

Được rồi, tôi bị thuyết phục. Tôi sẽ chia nhiều cặp ngoặc vuông bằng cách sử dụng một regex đơn giản, và sau đó chạy chức năng của bạn trên chúng. Điều này hoạt động quá độc đáo không sử dụng :) –

+0

Có nhiều cặp ngoặc vuông có nghĩa là '(html | php (4 | 5))'? Tôi không chắc tôi hiểu nhưng sẽ cập nhật mã nếu bạn có thể xác nhận điều này. Mã hiện tại chỉ khớp với cặp khung cuối cùng. –

4

Không chính xác những gì bạn đang hỏi, nhưng có gì sai khi chỉ lấy những gì bạn có để có được danh sách (bỏ qua | s), đặt nó vào một biến và sau đó explode ing trên | s? Điều đó sẽ cung cấp cho bạn một loạt các mặt hàng tuy nhiên có nhiều (bao gồm 1 nếu không có một | hiện tại).

+0

Đúng, điểm tốt. Hãy thử điều đó ngay bây giờ. –

5

Tôi nghĩ rằng bạn đang tìm kiếm:

/(([^ |] +) (| ([^ |] +)) +)/

Về cơ bản, đặt splitter '|' thành một mẫu lặp lại.

Ngoài ra, các từ của bạn nên được tạo thành 'không phải đường ống' thay vì 'không parens', theo yêu cầu thứ ba của bạn.

Ngoài ra, thích + đến * cho sự cố này. + có nghĩa là 'ít nhất một'.* có nghĩa là 'không hoặc nhiều hơn'.

+0

Chúc mừng @CWF, đây chính xác là những gì tôi đã yêu cầu. Tôi đã bỏ phiếu cho ngày hôm nay, nếu không tôi sẽ +1. Tôi sẽ xem xét điều này thêm một số ngày mai, tôi chưa chắc chắn làm thế nào để xây dựng các chuỗi biến thể, tôi có thể cần một preg_match_callback - sẽ cố gắng. Dù sao, cảm ơn rất nhiều đã cho các mô hình lặp đi lặp lại. –

2

Có lẽ tôi vẫn không nhận được câu hỏi, nhưng giả thiết của tôi là bạn đang chạy qua hệ thống tập tin cho đến khi bạn nhấn một trong những tác phẩm, trong trường hợp này bạn có thể do

$files = glob("$path/index.{htm,html,php,shtml}", GLOB_BRACE); 

Mảng kết quả sẽ chứa bất kỳ tệp nào khớp với tiện ích của bạn trong đường dẫn $ hoặc không có. Nếu bạn cần bao gồm tệp theo thứ tự tiện ích mở rộng cụ thể, bạn có thể foreach qua mảng có danh sách các tiện ích mở rộng được sắp xếp, ví dụ:

foreach(array('htm','html','php','shtml') as $ext) { 
    foreach($files as $file) { 
     if(pathinfo($file, PATHINFO_EXTENSION) === $ext) { 
      // do something 
     } 
    } 
} 

Edit: và có, bạn có thể có nhiều dấu ngoặc nhọn trong glob.

+0

Đó là * điều đó * dễ dàng. Cảm ơn Gordon. Tôi không biết Glob có thể làm những việc như thế. Tôi không thể trong lương tâm tốt không chấp nhận câu trả lời được đưa ra, như tôi đã yêu cầu cụ thể để làm thế nào để phân tích chuỗi, nhưng tôi sẽ đưa một lưu ý về câu trả lời của bạn vào câu hỏi. –

+0

Để tham khảo trong tương lai, thêm thông tin về 'GLOB_BRACE', với các ví dụ, tại đây: http://de.php.net/manual/en/function.glob.php#88250 –

+0

Thông báo lỗi nhỏ:' GLOB_BRACE' không khả dụng trên một số các hệ thống không phải GNU, bao gồm Solaris (nhưng được hỗ trợ trên Windows). Tôi sẽ cố gắng tìm hiểu xem chính xác những người thân nào http://stackoverflow.com/questions/2536924/glob-brace-portability –

1

Câu trả lời được đưa ra, nhưng đó là một câu đố hài hước và tôi chỉ không thể cưỡng lại

function expand_filenames2($str) { 
    $r = array($str); 
    $n = 0; 
    while(preg_match('~(.*?) \((\w+ \| [\w|]+) \) (.*) ~x', $r[$n++], $m)) { 
     foreach(explode('|', $m[2]) as $e) 
      $r[] = $m[1] . $e . $m[3]; 
    } 
    return array_slice($r, $n - 1); 
} 



print_r(expand_filenames2('/(a|b)/var/(ignore)/(www|www2)/index.(htm|html|php|shtml)!')); 

có lẽ điều này giải thích một chút lý do tại sao chúng ta thích regexps rằng có rất nhiều;)

+0

@stereofrog sweet !!! +1. Tuy nhiên, –

+0

@stereofrog, '\ w' sẽ cần được mở rộng thành một cái gì đó như' \ w \ d.' để khớp với bất kỳ tên tệp có thể tưởng tượng (tiêu chuẩn) nào. –

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