1 Востаннє редагувалося Replace (02.10.2012 01:36:42)

Тема: Фільтрація номерів за маскою (задача на 5+)

Є масив номерів:
096 954 35 20
093 666 35 20
067 555 23 20
096 951 23 23
...

Функція повинна повертати масив, який задовільняє переданій масці:
Які можуть бути маски: буквені та цифрові.

a - будь-яка цифра (не число)
b - будь-яка цифра, не може бути a
c - будь-яка цифра, не може бути a або b
і т.д.

Наприклад, масці aaa відповідають:

093 666 35 20
067 555 23 20

Масці abab відповідає:

096 951 23 23

Масці 3520:

096 954 35 20
093 666 35 20

2

Re: Фільтрація номерів за маскою (задача на 5+)

Список номерів для тестів. Краще читати з текстового файлу:

067 663-4400
067 66-33-5-22
067 66-33-6-44
067 860-9006
067 860-8-444
067 584-20-20
067 477-57-71
067 909-31-11
067 915-58-85
067 915-59-91
067 58-353-58
067 597-5000
067 596-17-17
067 663-7770
067 663-7337
067 663-45-45
067 909-333-5
067 915-2003
067 915-2006
067 915-2008
067 915-2009

+38 093 437 9999 
+38 063 834 7777
+38 063 991 6666
+38 093 129 3333  
+38 063 887 3333 
+38 093 117 2222
+38 093 518 2222  

+38 093 11 777 17 
+38 093 11 7777 6 
+38 093 11 7777 5 
+38 093 11 7777 4 
+38 063 88 00 777 
+38 093 11 77 333  
+38 093 11 777 99  

+38 093 117 22 33 
+38 063 4 131 131
+38 063 6 227 227
+38 063 411 9 411
+38 063 990 990 3
+38 093 12 8888 9 

+38 063 849 2000 
+38 093 129 3000  
+38 063 370 9 111 
+38 093 85 66 111 
+38 063 588 4 111 
+38 093 81 06 111 
+38 063 43 06 111 
+38 093 15 66 111  
+38 093 81 55 222 
+38 093 81 06 222 
+38 093 85 66 222 
+38 063 433 1 222 
+38 063 43 06 222 
+38 093 15 76 333  
+38 063 42 19 333 
+38 063 72 30 333 
+38 063 61 68 333 
+38 063 41 01 333 
+38 063 42 19 444 
+38 093 15 76 444    
+38 093 80 45 444 
+38 063 99 02 444 
+38 093 43 91 555 
+38 093 41 24 555 
+38 063 99 02 555 
+38 093 57 81 666 
+38 093 51 37 666 
+38 093 80 69 666 
+38 063 622 4 666 
+38 063 277 5 666
+38 093 15 80 666 
+38 063 83 73 666 
+38 093 15 75 666    
+38 093 65 72 777 
+38 093 85 49 777 
+38 093 85 49 888 
+38 063 61 84 888 
+38 093 85 65 888 
+38 093 15 65 888  
+38 093 15 75 888  
+38 063 588 3 999 
+38 093 51 37 999 
+38 063 78 78 999 
+38 093 1 29 2999 

+38 093 518 20 20 
+38 063 840 51 51 
+38 063 787 94 94 
+38 093 117 27 27 

+38 063 370 90 70
+38 063 990 99 11
+38 063 990 96 96
+38 063 990 97 97
+38 063 990 97 99
+38 063 990 96 99
+38 093 855 0003 
+38 093 855 00 44
+38 063 433 11 66
+38 063 433 11 88
+38 063 433 11 99
+38 063 787 89 89 
+38 063 990 991 9
+38 063 990 99 59

+38 093 1 2888 28  
+38 093 655 666 5
+38 063 991 24 24
+38 093 858 31 31
+38 093 858 42 42
+38 063 608 45 45
+38 063 313 46 46
+38 093 858 48 48
+38 093 858 53 53
+38 093 858 63 63
+38 063 991 67 67
+38 063 991 68 68
+38 063 622 74 74
+38 063 620 79 79
+38 063 622 81 81
+38 063 622 87 87
+38 063 787 90 09 
+38 063 99 1234 0

+38 063 84 555 44 
+38 063 84 555 05 

+38 063 991 22 99
+38 063 991 55 33
+38 063 991 55 00
+38 063 991 66 00
+38 063 454 66 11
+38 063 454 66 55
+38 063 991 66 88
+38 063 454 66 77

+38 063 99 11 880 
+38 093 655 67 66 
+38 063 991 16 16 

+38 093 80 69 699
+38 063 99 098 99
+38 063 990 99 30

+38 063 990 99 60 
+38 063 990 99 17 
+38 063 990 99 34 
+38 063 990 99 32 
+38 063 990 99 40 
+38 063 990 99 41 
+38 063 990 99 47 
+38 063 990 99 48 
+38 063 990 99 51 
+38 063 990 99 52 
+38 063 990 99 15 

+38 098 174 1000  
+38 098 172 8000  
+38 098 172 9000  
+38 097 01 68 111
+38 096 36 63 111
+38 097 02 89 222
+38 097 02 77 333
+38 067 78 57 333
+38 096 55 17 333
+38 067 11 68 333
+38 096 33 06 444
+38 096 33 07 555
+38 067 86 98 555
+38 097 040 8 666 
+38 067 86 19 666
+38 096 33 01 888
+38 097 02 92 888

+38 096 56 56 56 0 
+38 096 090 1 090
+38 096 096 34 34
+38 096 565 63 63 
+38 096 030 86 86
+38 096 030 85 85
+38 067 988 51 51
+38 067 988 48 48
+38 098 080 72 72 
+38 098 877 76 67
+38 097 444 10 05
+38 098 008 005 6
+38 097 02 1111 5

+38 096 56 55 44 3 
+38 097 444 11 34
+38 096 330 22 23
+38 096 330 34 33
+38 097 439 33 39
+38 067 867 77 67
+38 096 727 77 87
+38 096 727 97 57
+38 067 785 76 77
+38 097 029 29 59
+38 097 028 22 28
+38 067 86 56 566
+38 098 057 57 37
+38 098 07 57 577
+38 098 076 77 27
+38 098 068 38 58
+38 067 790 77 44
+38 096 661 55 66
+38 098 172 90 90 
+38 098 172 90 90 
+38 096 97 10 100
+38 097 96 10 100

+38 097 966 80 08
+38 098 55 90 900
+38 067 86 19991 
+38 096 747 0008 

+38 097 44 22 44 3
+38 096 33 8 22 11
+38 097 44 55 6 11
+38 096 330 55 00 
+38 096 33 11 8 55
+38 097 44 55 44 8
+38 097 44 55 0 11
+38 098 00 22 55 1
+38 098 00 22 55 2
+38 097 44 22 00 5
+38 096 330 22 00 
+38 097 44 3 55 77
+38 097 44 55 8 99
+38 096 33 8 11 33
+38 096 44 22 88 9
+38 097 44 55 22 6
+38 097 44 55 4 11
+38 097 44 22 00 3
+38 098 8 55 88 66 
+38 098 85 666 88  
+38 098 85 666 77  
+38 098 85 666 99  
+38 098 855 888 2  
+38 098 85 666 06  
+38 09 88 444 88 1 

+38 096 96 96 337 

+38 09 80 80 80 25 
+38 09 80 80 80 34

+38 098 057 66 76 
+38 098 06 111 77 
+38 098 00 111 34 
+38 097 02 666 55 
+38 097 02 666 16 
+38 0988 777 622  
+38 097 050 22 28 
+38 097 439 444 8 
+38 097 44 222 51 
+38 097 44 555 20 
+38 097 44 555 36 

+38 067 814 999 0 
+38 067 814 999 1 
+38 067 814 999 2 
+38 067 814 999 3 
+38 067 814 999 4 
+38 067 814 999 5 
+38 067 814 999 6 

+38 098 466 39 39
+38 096 677 00 10
+38 097 966 00 96
+38 098 98 97 008
+38 097 766 14 14
+38 097 766 13 31
+38 098 71 07 111 
+38 096 07 42 444 
+38 097 766 1 555
+38 098 98 96 995

+38 098 886 0 688
+38 097 9 54321 6
+38 097 8 6666 89
+38 097 866 67 66

+38 050 100 44 14
+38 050 181 1 180
+38 095 855 1234
+38 099 030 999 0
+38 095 545 000 6

+38 066666 45 15
+38 066666 39 44
+38 066666 32 33
+38 066666 51 44
+38 066666 14 94
+38 066666 28 09
+38 066666 34 15
+38 066666 23 16
+38 066666 14 14

+38 099 24 74 111 
+38 066 35 48 111
+38 095 38 57 222
+38 095 48 15 444
+38 066 37 25 444
+38 095 38 57 444
+38 050 05 24 666

3

Re: Фільтрація номерів за маскою (задача на 5+)

Є питання? Яка мета даної задачі просто для розваг чи оприділення самого крутого номеру ;)

Re: Фільтрація номерів за маскою (задача на 5+)

funivan написав:

Є питання? Яка мета даної задачі просто для розваг чи оприділення самого крутого номеру ;)

Швидше для розвитку логічного мислення.

Подякували: Replace1

5

Re: Фільтрація номерів за маскою (задача на 5+)

А що таке "маска"? А може бути така маска "!"№;%(*:?:"?

Щоб зрозуміти рекурсію потрібно спочатку зрозуміти рекурсію.
int fac(int n) { return n < 2 ? 1 : n*fac(n-1); }

6

Re: Фільтрація номерів за маскою (задача на 5+)

Для розвитку логіки :)
Можуть бути лише букви від a до z. Букві відповідає цифра від 1 до 9. Одній букві - одна цифра.

7

Re: Фільтрація номерів за маскою (задача на 5+)

Майже забацав є один нюанс.

Маска aba може відповідати цифрам 999 ?

Подякували: Replace1

8 Востаннє редагувалося funivan (01.10.2012 10:24:34)

Re: Фільтрація номерів за маскою (задача на 5+)

/**
 * @author Ivan Scherbak funivan.com
 */
class PhonesFinder {

  public static function findByMask($mask, $phones) {
    if (!preg_match('!^([a-z0-9]+)$!', $mask)) {
      throw new Exception('Mask not valid. [a-z] and [0-9] only');
    }

    if (empty($phones)) {
      return array();
    }

    $maskChars                = str_split($mask);
    $usedLettersInSubpatterns = array();


    # prepare mask for regex
    foreach ($maskChars as $maskCharIndex => $maskChar) {
      if (preg_match('!^[0-9]$!', $maskChar)) {
        #
        $maskChars[$maskCharIndex] = $maskChar;
      } else {
        # is letter
        $subPattern = '(?<' . $maskChar . '>[0-9])';
        if (isset($usedLettersInSubpatterns[$maskChar])) {
          $maskChars[$maskCharIndex] = '(?P=' . $maskChar . ')';
        } else {
          $maskChars[$maskCharIndex]           = $subPattern;
          $usedLettersInSubpatterns[$maskChar] = $maskChar;
        }
      }
    }


    $pattern = '!' . implode('', $maskChars) . '!';
    # our pattern for preg match is ready



    $phones      = (array) $phones;
    $validPhones = array();
    foreach ($phones as $phone) {
      $phoneInputNumber = $phone;
      $phone            = preg_replace('![^0-9]!', '', $phone);

      if (preg_match_all($pattern, $phone, $match)) {


        # [aba] pattern is not 999 [aba] is 090 for example
        # validate this rule
        for ($i = 0; $i < count($match[0]); $i++) {
          $isValidPhone      = true;
          $usedNumbersInMask = array();

          foreach ($usedLettersInSubpatterns as $char) {
            $number = $match[$char][$i];
            if (in_array($number, $usedNumbersInMask)) {
              $isValidPhone = false;
            } else {
              $usedNumbersInMask[] = $number;
            }
          }

          if ($isValidPhone === true) {
            break;
          }
        }

        if ($isValidPhone === true) {
          $validPhones[] = $phoneInputNumber;
        }
      }
    }

    return $validPhones;
  }

}

$mask        = 'aba99';
$phonesArray = array(
    '38099 0309990'
);
$validPhones = PhonesFinder::findByMask($mask, $phonesArray);
echo '<pre>' . __LINE__ . '***' . print_r($validPhones, true) . '</pre>';

Код готовий. Перевіряємо ;)

Подякували: Replace1

9

Re: Фільтрація номерів за маскою (задача на 5+)

funivan написав:

Майже забацав є один нюанс.

Маска aba може відповідати цифрам 999 ?

Ні, не може :)

Перевірив. Все працює.

Респект.

10

Re: Фільтрація номерів за маскою (задача на 5+)

Ось мій варіант кому цікаво, але крім буквених масок ще можливі номер з датою (рік від 1950 до 2050), зеркало та послідовності однакових цифр:

function pattern_match($number, $pattern) {
        
        if (!isset($pattern) || empty($pattern)) return true;
        
        $number = preg_replace("/[^0-9]/","",$number);    
        
        $pattern_len = strlen($pattern);
        $number_len = strlen($number);
        
        
        if ($number_len == 10) {
            $number = substr($number, 3);
            $number_len = strlen($number);
        }
        
        if ($pattern == 'номер з датою') {
            $start_date = 1910;
            $end_date = 2050;
            $date = $start_date;
            
            while ($date < $end_date) {
                if (strpos($number, (string) $date) == 3)
                    return true;
                $date++;
            }
        }
        
        if ($pattern == 'зеркало') {
            $number_z[] = $number;
            $number_z[] = substr($number, 1, 6);
            $number_z[] = substr($number, 2, 5);
            $number_z[] = substr($number, 3, 4);
        
                
            foreach($number_z as $z) {
                $i = 0;
                $j = strlen($z) - 1;
                while($z[$i] == $z[$j]) {
                    if ($i > $j) {
                        return true;
                    }
                    $i++;
                    $j--;
                }
            }
            
            return false;    
            
        }
        
        if ($pattern == 'дві цифри' || $pattern == '2 цифри') {
            return (strlen(count_chars($number, 3)) === 2);
        }
        
        
        if ($pattern == 'три цифри' || $pattern == '3 цифри') {
            return (strlen(count_chars($number, 3)) === 3);
        }
        
        if ($pattern == 'чотири цифри' || $pattern == '4 цифри' || $pattern == 'чотири цифри') {
            return (strlen(count_chars($number, 3)) === 4);
        }
        
        if ($pattern == "п'ять цифр" || $pattern == '5 цифр') {
            return (strlen(count_chars($number, 3)) === 4);
        }
        
        
        if ($pattern == 'шість цифр' || $pattern == '6 цифр') {
            return (strlen(count_chars($number, 3)) === 4);
        }
        
        
        if ($pattern == 'сім цифр' || $pattern == '7 цифр') {
            return (strlen(count_chars($number, 3)) === 7);
        }
                    
        $number_pattern = preg_replace("/[^0-9]/","",$pattern);
        if (strlen($number_pattern) == 0) {
            $pattern = preg_replace("/[^a-zA-Z]/","",$pattern);
        } else {
            if (strpos($number, $number_pattern) === false) {
                return false;
            } else {
                return true;
            }
        }
                
        $size = $number_len - $pattern_len + 1;
        
        if ($size < 1) {
            return false;
        }
        
        $ngram = array();
        
        for ($i = 0; $i < $size; $i++) {
            $ngram = substr($number, $i, $pattern_len);
            
            $arr = array();
            
            $flag = true;
            
            for ($j = 0; $j < $pattern_len; $j++) {
                if (array_key_exists($pattern[$j], $arr)) {
                    if ($arr[$pattern[$j]] != $ngram[$j]) {
                        $flag = false;
                        break;
                    }
                } else {
                    $arr[$pattern[$j]] = $ngram[$j];
                }
            }
            
            if ($flag) {
                return true;
            }
            
        }
        
        return false;
    }
Подякували: Patron1

11

Re: Фільтрація номерів за маскою (задача на 5+)

Так код досить цікавий.
Таких задач як він виконує не ставилось)

У мене теж умови можуть бути різні наприклад маски

aba45
aa22cc
2020

Маска зеркало у вашому коді, під які телефонні номера мала попадати?

Взагалі крутизну номерів я визначав за принципом.
Рахував скільки унікальних цифр в номері
Виходило чим менше унікальних цифр тим краще =)

12

Re: Фільтрація номерів за маскою (задача на 5+)

(096) 511-12-11 - 4 символи
(096) 4-66-67-66 - 5 символів
(096) 380-80-08 - 4 символи
(096) 11-2222-1 - 6 символів

Коли є ланцюжок-зеркало довжиною більше ніж 3 символи :)

13

Re: Фільтрація номерів за маскою (задача на 5+)

Replace написав:

(096) 511-12-11 - 4 символи
(096) 4-66-67-66 - 5 символів
(096) 380-80-08 - 4 символи
(096) 11-2222-1 - 6 символів

Коли є ланцюжок-зеркало довжиною більше ніж 3 символи :)

Ясно =) Оригінальна задумка ;)

14

Re: Фільтрація номерів за маскою (задача на 5+)

Функцію можна використовувати для оцінки вартості телефонних номерів. Хоча, в принципі, для оцінки номерів ICQ теж підійде, але там довжина скакає від 5 до 10.
Як фільтр для користува на сайті з продажу номерів теж непогано підійде.

15

Re: Фільтрація номерів за маскою (задача на 5+)

$phone = '5111211';
echo 100 / count(array_count_values(str_split($phone))).'%';

Оцінка по самому головному фактору в лоб =)
Підходить для визначення як icq так телефонних номерів.

Replace - а я голову ламаю для чого дзеркало потрібне )))  Якщо всі фактори взяти до уваги тоді може вийти непоганий оцінювач ;)

16

Re: Фільтрація номерів за маскою (задача на 5+)

Я оптимізував рішення Replace але замінив реалізацію вибору по буквенній масці. Просто конвертую букви в їх ASCII коди і віднімаю 97 щоб перша буква алфавіту ("a") давала число 1 а буква z число 32.

function pattern_match($number, $pattern) {
        
        if (!isset($pattern) || empty($pattern)) return true;
        
        $number = preg_replace("/[^0-9]/","",$number);    
        
        $pattern_len = strlen($pattern);
        $number_len = strlen($number);
        
        
        if ($number_len == 10) {
            $number = substr($number, 3);
            $number_len = strlen($number);
        }
        
        /*
        * одним рядком
        */
        if ($pattern == 'номер з датою') {
            return preg_match("#19[1-9][0-9]|20[0-5][0-9]#", $number);
        }   
        
        /*
        *    дзекало яких завгодно великих номерів
        */
        if ($pattern == 'дзеркало') {
            $i = 0;
            $j = $number_len - 1;            
            do {            
                if($number[$i] == $number[$j]){    
                } else {
                    return false;
                }
                if($i == $j - 1){
                    return true;
                }
                $i++; $j--;                        
            } while($i < $j);    
            return false;
        }
        
        /*
        *    можна задавати скільки завгодно цифр
        *    у форматі "3 цифри", "54 цифри"
        */
        if(preg_match("#([0-9]*)\s+цифр(и|а)?#", $pattern, $matches)) {
             return (strlen(count_chars($number, 3)) === (int) $matches[1]);
        }
                                   
        $number_pattern = preg_replace("/[^0-9]/","",$pattern);
        if (strlen($number_pattern) == 0) {
            $pattern = preg_replace("/[^a-zA-Z]/","",$pattern);
        } else {
            return strpos($number, $number_pattern);
        }
                
        /* 
        *Початок поршуку по символьній масці 
        *Буква a конвертується в 1, b в 2, z в 32
        */
        $convert = "";
        for($i = 0; $i < strlen($pattern); $i++){
            $convert .= ord(mb_substr($pattern, $i, 1, "UTF-8"))-96;
        }
        return preg_match("#".$convert."#", $number);
    }

if(pattern_match("123456789987654321", "дзеркало")){
        // тут
        echo "true";
    } else {
        echo "false";
    }
    echo "<br/>";
    
    if(pattern_match("1245", "4 цифри")){
        // тут
        echo "true";
    } else {
        echo "false";
    }
    echo "<br/>";
    if(pattern_match("12456", "4 цифри")){
        echo "true";
    } else {
        // тут
        echo "false";
    }
    echo "<br/>";
    if(pattern_match("097123", "abc")){
        // тут
        echo "true";
    } else {
        echo "false";
    }
    echo "<br/>";
    if(pattern_match("097123", "adc")){
        echo "true";
    } else {
        // тут
        echo "false";
    } 
Щоб зрозуміти рекурсію потрібно спочатку зрозуміти рекурсію.
int fac(int n) { return n < 2 ? 1 : n*fac(n-1); }

17 Востаннє редагувалося Replace (02.10.2012 01:20:58)

Re: Фільтрація номерів за маскою (задача на 5+)

*Буква a конвертується в 1, b в 2, z в 32

ось тут облом =)


a - будь-яка цифра (не число)
b - будь-яка цифра, яка не дорівнює a
c - будь-яка цифра, яка не дорівнює a та b


Наприклад, масці aaa відповідають:
093 666 35 20 // a = 6
067 555 23 20 // a = 5

Масці abab відповідає:
096 951 23 23 // a = 2 ; b = 3

З цифрами теж облом. Там мається на увазі 4 однакові цифри підряд.

18

Re: Фільтрація номерів за маскою (задача на 5+)

я по іншому маски зрозумів

Щоб зрозуміти рекурсію потрібно спочатку зрозуміти рекурсію.
int fac(int n) { return n < 2 ? 1 : n*fac(n-1); }

19

Re: Фільтрація номерів за маскою (задача на 5+)

в мене не облом, в мене інша функція) А те що мається на увазі то в кожного своє)

Там мається на увазі 4 однакові цифри підряд.

- в мене мається на увазі 4 унікальні цифри.

Щоб зрозуміти рекурсію потрібно спочатку зрозуміти рекурсію.
int fac(int n) { return n < 2 ? 1 : n*fac(n-1); }
Подякували: Replace1

20

Re: Фільтрація номерів за маскою (задача на 5+)

Цифри - ок. В умові взагалі про це не було сказано. Можна і так використовувати.
А такі маски точно не мають ніякого застосування. =)