Javascript-форум (https://javascript.ru/forum/)
-   Серверные языки и технологии (https://javascript.ru/forum/server/)
-   -   Поиск части слова (https://javascript.ru/forum/server/70463-poisk-chasti-slova.html)

Sonya 06.09.2017 17:48

Поиск части слова
 
Здравствуйте!
Помогите, пожалуйста, с такой задачей:
Для поиска повторяющегося набора цифр (кода), использую такой код:
$file=file("test.txt");
    $str=$file[0];
    $array=explode(",",$str);
	$value=1;
    if(($key = array_search($value,$array)) !== FALSE){
     unset($array[$key]);
     }
    $first_array = array_count_values($array);
    $second_array = array_diff($first_array, [$value]);
    var_dump($second_array);

который выводит, число вхождений (повторений) кода. Задача в том, что $file=file("test.txt"); ищет строгое соответствие, а надо, скажем, при совпадении, например, первых 5 цифр (как по маске), чтобы считался повтор. Как это можно реализовать?

Nexus 06.09.2017 18:15

Цитата:

Сообщение от Sonya
$file=file("test.txt"); ищет строгое соответствие,

Функция «file» ничего не ищет, а читает файл, разбивает его по строчкам и возвращает массив этих строк.

Что нужно сделать не понял.

laimas 06.09.2017 18:23

Цитата:

Сообщение от Sonya
$str=$file[0];
$array=explode(",",$str);

Здесь $str живет короче мгновения и далее используется один раз, зачем же вы ее определяете, а не сразу?

$array = explode(",", $file[0]);


Цитата:

Сообщение от Sonya
первых 5 цифр (как по маске)

Какой маске?

Sonya 06.09.2017 18:45

По как по "маске" - имела ввиду соответствие, но не строгое, поэтому "как". Да можно без "$str", сделать сразу, осталось, т.к. код несколько раз трансформировался. Безусловно, функция «file» ничего не ищет. А сделать нужно, чтобы код выполнял ту же работу, что и сейчас, с той лишь разницей, что сейчас поиск вхождений ищет идентичность строк кода 1234567, а надо, чтобы принимался код, например, и 1234576, или 1234598 и т.д.

Sonya 06.09.2017 18:49

Т.е., например, 5 цифр кода при повторе кода, принимались в строгом соответствии, а последующие не имели принципиального значения.

Nexus 06.09.2017 19:37

Sonya, нужно что-то типа этого?
<?php
    $haystack=array('123456','123789','124987','321654');
    $needle='123';
    $result=array();
    
    $charset='UTF-8';
    $needle_length=mb_strlen($needle,$charset);
    foreach($haystack as $string){
        if(mb_substr($string,0,$needle_length,$charset)==$needle)
            $result[]=$string;
    }
    
    var_dump($result);
    exit;

Sonya 06.09.2017 19:44

Дело в том, что я не знаю цифры кодов в массиве, они будут выводиться, только в случае повтора.

laimas 06.09.2017 20:00

Nexus,
цифры, латиница, управляющие символы в монгобайтной кодировке все равно занимают один байт, $charset='UTF-8' и mb_strlen для них совсем не требуется.

laimas 06.09.2017 20:05

Цитата:

Сообщение от Sonya
надо, чтобы принимался код, например, и 1234576, или 1234598

Цитата:

Сообщение от Sonya
Дело в том, что я не знаю цифры кодов в массиве

Значит ищите по совпадениям - совпали первые N у набора М, это один набор, совпали К у набора I, это другой набор. Так что-ли или "маска" фиксированная по длине?

Sonya 06.09.2017 20:17

Цитата:

Сообщение от laimas (Сообщение 463909)
Значит ищите по совпадениям - совпали первые N у набора М, это один набор

- в этом и проблема - реализовать применимо к коду. С чего начать?
Цитата:

Сообщение от laimas (Сообщение 463909)
Так что-ли или "маска" фиксированная по длине?

- да, будет по длине фиксированной.

laimas 06.09.2017 20:34

Цитата:

Сообщение от Sonya
да, будет по длине фиксированной.

Ну если фиксирована длина, то проще - array_filter и в нем проверять на совпадения от начала на длину маски.

http://fi2.php.net/manual/ru/function.array-filter.php
http://fi2.php.net/manual/ru/function.strstr.php

laimas 06.09.2017 20:42

Возможно я не понял - фиксированная, это знаем что к примеру 4 символа, но не знаем какие именно?

Nexus 06.09.2017 20:43

Цитата:

Сообщение от laimas (Сообщение 463907)
Nexus,
цифры, латиница, управляющие символы в монгобайтной кодировке все равно занимают один байт, $charset='UTF-8' и mb_strlen для них совсем не требуется.

Ну так это в моем коде только циферки используются, что действительно в файле находится и что необходимо искать - я без понятия.

Sonya 06.09.2017 20:45

Цитата:

Сообщение от laimas (Сообщение 463912)
Возможно я не понял - фиксированная, это знаем что к примеру 4 символа, но не знаем какие именно?

Да, именно так, сейчас буду разбираться по ссылкам.

Sonya 06.09.2017 20:58

Цитата:

Сообщение от Nexus (Сообщение 463913)
Ну так это в моем коде только циферки используются, что действительно в файле находится и что необходимо искать - я без понятия.

Только цифры.

Nexus 06.09.2017 21:10

Функция «func» ищет в списке слов те, которые начинаются на одни и те же символы; принимает массив слов и длину строки; возвращает искомое, как массив.
<?php

	function func(array $words,$length){
		$ch='UTF-8';
		$results=array();
		foreach($words as $string){
			if(mb_strlen($string,$ch)<$length) 
				continue;
			
			$str=mb_substr($string,0,$length,$ch);
			if(!isset($results[$str]))
				$results[$str]=array();
				
			$results[$str][]=$string;
		};
		
		return (array_map(function($vals){
			return array_unique($vals);
		},array_filter($results,function($vals){
			return count($vals)>1;
		})));
	};

	$string='Lorem Ipsum - это текст-"рыба", часто используемый в печати и вэб-дизайне. Lorem Ipsum является стандартной "рыбой" для текстов на латинице с начала XVI века. В то время некий безымянный печатник создал большую коллекцию размеров и форм шрифтов, используя Lorem Ipsum для распечатки образцов. Lorem Ipsum не только успешно пережил без заметных изменений пять веков, но и перешагнул в электронный дизайн. Его популяризации в новое время послужили публикация листов Letraset с образцами Lorem Ipsum в 60-х годах и, в более недавнее время, программы электронной вёрстки типа Aldus PageMaker, в шаблонах которых используется Lorem Ipsum.';
	
	$string=preg_replace('#\W+?#uim',',',mb_strtolower($string,'UTF-8'));
	$string=array_filter(explode(',',$string));
	var_dump(func($string,5));
	exit;

Sonya 06.09.2017 21:11

Цитата:

Сообщение от laimas (Сообщение 463911)
Ну если фиксирована длина, то проще - array_filter и в нем проверять на совпадения от начала на длину маски.

В фильтре вставить strstr с параметрами от первого до n-го символа?

Sonya 06.09.2017 21:21

Цитата:

Сообщение от Nexus (Сообщение 463916)
Функция «func» ищет в списке слов те, которые начинаются на одни и те же символы; принимает массив слов и длину строки; возвращает искомое, как массив.

Пыталась использовать код по поиску по словам, но при определенной длине строки из цифровых кодов, он просто переставал работать. Кодов может быть очень много, именно поэтому решила использовать код, который выложила. Чтобы было понятно о размере, то до 500 000 кодов, данный проверяла почти на 700 000, работает очень быстро, память не грузит.

Nexus 06.09.2017 21:31

Sonya, или я очень устал, или вы действительно изъясняетесь так, что вас невозможно понять...

У вас есть:
1. файл, который содержит список чисел, разделенных запятыми;
2. длинна искомой строки.

Нужно:
Определить сколько слов имеет одинаковое начало и вернуть список этих слов.

Верно?

Код, что я привел зависает, если ему передать на обработку массив длинною в пол миллиона элементов?

laimas 06.09.2017 21:40

Цитата:

Сообщение от Sonya
В фильтре вставить strstr с параметрами от первого до n-го символа?

Нет, если неизвестна сама маска, а только ее длина, то strstr не нужен, нужно брать отрезок равный длине символов.

laimas 06.09.2017 21:40

Nexus,
нет ничего подпадающее под разбор UTF, что вы уперлись в mb_?

Nexus 06.09.2017 21:44

Цитата:

Сообщение от laimas (Сообщение 463922)
Nexus,
нет ничего подпадающее под разбор UTF, что вы уперлись в mb_?

Действительно (сарказм).
<?php

	function func(array $words,$length){
		$results=array();
		foreach($words as $string){
			if(strlen($string)<$length) 
				continue;
			
			$str=substr($string,0,$length);
			if(!isset($results[$str]))
				$results[$str]=array();
				
			$results[$str][]=$string;
		};
		
		return (array_map(function($vals){
			return array_unique($vals);
		},array_filter($results,function($vals){
			return count($vals)>1;
		})));
	};

	$string='Lorem Ipsum - это текст-"рыба", часто используемый в печати и вэб-дизайне. Lorem Ipsum является стандартной "рыбой" для текстов на латинице с начала XVI века. В то время некий безымянный печатник создал большую коллекцию размеров и форм шрифтов, используя Lorem Ipsum для распечатки образцов. Lorem Ipsum не только успешно пережил без заметных изменений пять веков, но и перешагнул в электронный дизайн. Его популяризации в новое время послужили публикация листов Letraset с образцами Lorem Ipsum в 60-х годах и, в более недавнее время, программы электронной вёрстки типа Aldus PageMaker, в шаблонах которых используется Lorem Ipsum.';
	
	$string=preg_replace('#\W+?#uim',',',strtolower($string));
	$string=array_filter(explode(',',$string));
	var_dump(func($string,5));
	exit;

laimas 06.09.2017 21:51

Sonya,
и array_filter тоже в таком случае не годится. Нет сейчас времени, а словами это так:

обычный цикл for, опрашивать сразу по два крайних элемента массива, двигаясь к центру массива

числа равные длине маски, это ключи, если такого нет, создаем и под ним помещаем элементы, у которых число начинается с этого ключа

в полученном массиве взять те, у которых вложения не пустые (или удалить такие)

Nexus 06.09.2017 22:32

<?php
	header('Content-Type: text/html; charset=utf-8');
	ini_set('memory_limit','512M');
	
	function func(array $words,$length){
		if(count($words)%2==1)
			$words[]='';
		
		$words=array_values($words);
		$results=array();
		for($i=0,$j=count($words)-1;$i<$j;$i++,$j--){
			foreach(array($i,$j) as $key)
				if(strlen($words[$key])>=$length){
					$str=substr($words[$key],0,$length);
					$results[$str][]=$words[$key];
				};
		};
		
		return array_map(function($vals){
            return array_unique($vals);
        },array_filter($results,function($vals){
            return count($vals)>1;
        }));

	};

	$array=array();
	$i=1000000;
	while($i--)
		$array[]=mt_rand(0,mt_getrandmax());
		
	$start=microtime(true);
	$res=func($array,3);
	echo 'Найдено ',count($res),' результатов за ',number_format(microtime(true)-$start,3,'.',' '),' сек.';
	exit;

Sonya 06.09.2017 22:33

Цитата:

Сообщение от Nexus (Сообщение 463920)
Sonya, или я очень устал, или вы действительно изъясняетесь так, что вас невозможно понять...

У вас есть:
1. файл, который содержит список чисел, разделенных запятыми;
2. длинна искомой строки.

Нужно:
Определить сколько слов имеет одинаковое начало и вернуть список этих слов.

Верно?

Код, что я привел зависает, если ему передать на обработку массив длинною в пол миллиона элементов?

Да.

Sonya 06.09.2017 23:04

Только не слов, а цифровых кодов.

laimas 11.09.2017 04:23

$a = [
    1234576,
    2456901,
    1234598,
    2456776,
    2456993,
    1234567,
    1234555,
    3245089
];

$len = 4;

for($i = 0, $j = count($a)-1, $k = ceil(count($a)/2); $i < $k; $i++, $j--) {
    $group[substr($a[$i], 0, $len)][] = $a[$i];
    $group[substr($a[$j], 0, $len)][] = $a[$j];  
}

print_r($group);

print_r(array_values($group));

Sonya 16.09.2017 10:13

Спасибо!

laimas 16.09.2017 12:48

Цитата:

Сообщение от Sonya
Спасибо!

Не за что. Я не знаю что за такой пакет этих цифр, но учтите, что если их количество в массиве будет не четным, то в результирующем массиве будет дубликат одного значения. Если нечетное число также ожидается, тогда нужно так:

$a = [
    1234579,
    2456901,
    1234598,
    2456776,
    2456993,
    1234567,
    1234555,
    3245089,
    1234778
];
 
$len = 4;

if(count($a) & 1) array_push($a, null); //дополнить массив до четного
 
for($i = 0, $j = count($a)-1, $k = count($a)/2; $i < $k; $i++, $j--) {
    $group[substr($a[$i], 0, $len)][] = $a[$i];
    if($a[$j]) $group[substr($a[$j], 0, $len)][] = $a[$j]; 
}
 
print_r($group);
 
print_r(array_values($group));


Часовой пояс GMT +3, время: 00:36.