Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Удалить повторы слов в файле
Форумы портала PHP.SU » » Вопросы новичков » Удалить повторы слов в файле

Страниц (1): [1]
 

1. seowin - 30 Сентября, 2015 - 14:06:25 - перейти к сообщению
Помогите, пожалуйста, написать скрипт.

Задача следующая.
Есть txt файл, в котором строки формата:

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

Иногда слова в пределах разных строк повторяюся.

Задача - удалить повторы слов.

Т.е. не выходе должно быть:
абдикация|отречение
абзац|часть|отрывок|кусок|рождать
абитуриент|ученик|институтка|академист
абонировать|нанимать|рядить
абордаж|столкновение|сцепка|свалка
абориген|житель|туземец
абортировать
абракадабра|бессмыслица|белиберда|нелепость|ахинея|нелепица|чепуха
абсолютно|полностью|вполне|бесспорно|безусловно|непременно|совершенно
абстрактный|духовный|отвлеченный
абсурд|бред|бреда|вздор

Ломал голову, так и не смог написать рабочий вариант скритпа.

Не доходит, как пересохранить строку в файле.

Накидал пока вот что:
PHP:
скопировать код в буфер обмена
  1. <?PHP
  2.  
  3. $file = file('1.txt');
  4.  
  5. for($a = 0; $a < count($file); $a++) {
  6.  
  7.         $file[$a] = trim($file[$a]);
  8.        
  9.         $ex = explode('|', $file[$a]);
  10.        
  11.         foreach($ex as $val) {
  12.        
  13.         for($i = 0; $i < count($ex); $i++) {
  14.        
  15.                 for($j = $a + 1; $j < count($file); $j++) {
  16.                         if(strpos($file[$j], $ex[$i])) {
  17.                         str_replace($ex[$i], "", $file[$j]) . "<br/>";
  18.                         }
  19.                 }
  20.  
  21.         }
  22.  
  23. }
  24.  
  25. ?>
2. dcc0 - 30 Сентября, 2015 - 14:34:26 - перейти к сообщению
Примерно вижу так:
1. Читаем файл-источник.
2. Сохраняем во временный файл весь словарь, т.е. первые слова до знака |.
3. Читаем временный файл построчно, каждую строку (одно слово) ищем в файле-источнике, если найдено и если слово стоит не на первой позиции, то удаляем.
Как сохранить? Пишем строки, в которых не нашли, в новый файл, в которых нашли тоже пишем в новый файл, но без повтора.
Когда дойдем до последней строки во временном файле, удалим временный файл, удалим старый файл и переименуем новый, присвоив ему имя старого.

Т.е. как я понимаю, надо взять первое слово, пробежаться по всему файлу, удалить, потом взять второе и т.д.
Тот код, который Вы написали, похоже, не является решением.
3. neokiev - 30 Сентября, 2015 - 16:05:19 - перейти к сообщению
Если слов не очень много, то простой способ:
CODE (htmlphp):
скопировать код в буфер обмена
  1.  
  2. //читаем данные из файла
  3. $contents = file_get_contents('data.txt');
  4. //делаем массив - удаляем ненужные переносы строк и прочее
  5. $arrayOfWords = explode('|',  preg_replace('/\s+/', '',($contents)));
  6. //вуаля массив без дубликатов
  7. var_dump(array_unique($arrayOfWords));
  8. //дальше если нужно
  9. $result = implode('|', array_unique($arrayOfWords));
  10.  


Также если нужно учитывать верхний и нижний регистр слов - то смотрим в сторону strtolower
4. seowin - 30 Сентября, 2015 - 17:12:48 - перейти к сообщению
neokiev пишет:
Если слов не очень много, то простой способ:


Нужно, чтобы строки имели точно такой же вид, как в исходном файле, так как это база синонимов. Каждая строка отвечает за свой синонимичный ряд
5. neokiev - 30 Сентября, 2015 - 17:34:34 - перейти к сообщению
хорошо, нужно было описать изначально в задаче, дальше: в какой строке нужно удалять дубликат? если он есть?
(Добавление)
Код работает:
тестовые данные data.txt
CODE (htmlphp):
скопировать код в буфер обмена
  1.  
  2. asdfjasdjf|fasdfasdfas|afsdfasdfs
  3. ggggggg|ffffff|adsasda|
  4. fff|1234|8888|fffff|fff
  5. kasd|ROFL|ROFL
  6. ROFL|asda|9999
  7. OOOOP|kiko|NIKO
  8. NIKO|BOOM|LIQUID
  9.  


результат
newfile.txt
CODE (htmlphp):
скопировать код в буфер обмена
  1. asdfjasdjf|fasdfasdfas|afsdfasdfs
  2. ggggggg|ffffff|adsasda
  3. fff|1234|8888|fffff
  4. kasd|ROFL
  5. asda|9999
  6. OOOOP|kiko|NIKO
  7. BOOM|LIQUID



CODE (htmlphp):
скопировать код в буфер обмена
  1.  
  2. <?php
  3. //читаем данные из файла
  4. $contents = file_get_contents('data.txt');
  5.  
  6. //разбиваем данные по переносу строк
  7. $default = explode("\n", $contents);
  8.  
  9. $newOne = array();
  10. $appearances = array();
  11.  
  12. foreach ($default as $first => $line) {
  13. //разбиваем каждый елемент на слова
  14.    $exploded = explode('|', $line);
  15. //проходим по каждому слову
  16.   foreach($exploded as $currentItem) {
  17. //проверяем что бы елемент был не пустой, и не повторялся
  18.       if ($currentItem !== '' && !in_array($currentItem, $appearances)) {
  19.           //добавляем елемент в массив $appearances который позволяет
  20.           //исключит дубликаты
  21.           $appearances[] = $currentItem;
  22.          
  23.           $newOne[$first] .= $currentItem . '|';
  24.       }
  25.   }
  26. }
  27. //проходим по массиву новому
  28. //и удаляем последний | и добавляем вместо него перенос строки
  29. //тут можно заменить на str_replace/substrreplace
  30. $resulting = array_map(function($element) {
  31.   $removeLast = substr($element, 0, -1);
  32.    return $removeLast . "\n";
  33. }, $newOne);
  34.  
  35. $writeToFile = implode("",$resulting );
  36.  
  37. $file = fopen('newfile.txt', 'w+');
  38. fwrite($file, $writeToFile);
  39. fclose($file);
  40.  
  41.  
  42.  


код можно немного доработать, также посмотреть что бы небыло проблем с кодировкой
6. dcc0 - 30 Сентября, 2015 - 21:12:03 - перейти к сообщению
neokiev, я почему-то думаю, что решение не совсем верное.
Код несколько нарушил порядок в результате.
7. neokiev - 30 Сентября, 2015 - 21:46:34 - перейти к сообщению
dcc0 пишет:
Код несколько нарушил порядок в результате.

Ниндзя Не вижу где? Пример можно?) Подмигивание

dcc0 пишет:
neokiev, я почему-то думаю, что решение не совсем верное.

Это одно из решений. Которое можно доработать, я подсказал направление.
8. dcc0 - 30 Сентября, 2015 - 22:26:16 - перейти к сообщению
Было ROFL|asda
Стало ROFL asda

Тут нужно уточнение автора. Я так понимаю - это
своебразеый словарь синонимов. Тут может быть важным порядок следования знаков, количество строк.
(Добавление)
Проще говоря, пример автора и Ваш результат мало изоморфны.
9. neokiev - 30 Сентября, 2015 - 22:55:35 - перейти к сообщению
dcc0 пишет:

Было ROFL|asda
Стало ROFL asda


не верно вот что было и стало
CODE (htmlphp):
скопировать код в буфер обмена
  1.  
  2. kasd|ROFL|ROFL
  3. ROFL|asda|9999
  4.  
  5.  
  6. kasd|ROFL
  7. asda|9999
  8.  

это разные строки.

Суть даже не в этом, задача до конца не сформулирована. Автор, если есть возможность приведите полный пример файла, и уточните в каких случаях удалять, спасибо.
10. seowin - 01 Октября, 2015 - 08:24:51 - перейти к сообщению
Спасибо за помощь.

Проверил, результат получился таким:
абдикация|отречение
абзац|часть|отрывок|кусок|рождать
абитуриент|ученик|институтка|академист
абонировать|нанимать|рядить
абордаж|столкновение|сцепка|свалка
абориген|житель|туземец
абортировать
абракадабра|бессмыслица|отречение|белиберда|нелепость|ахинея|нелепица|чепуха
абсолютно|полностью|вполне|бесспорно|безусловно|непременно|совершенно
абстрактный|духовный|отвлеченный
абсурд|бред|бреда|вздор

Т.е. не удалился повтор слова "отречение".

Полный файл имеет около 15 тыс. строк.

Нужно, чтобы каждое слово в файле встречалось всего 1 раз.
Т.е. алгоритм следующий:
1. разбиваем строку на слова
2. ищем вхождение каждого слова в каждой строке последующей строке
3. если вхождение найдено, заменяем его на ""

На выходе должен быть файл, в котором:
а) строки имеют такой же вид, как в первоначальном файле
б) заменены все повторы слов на ""

Ничего страшного, если будут строки такого вида:
абордаж||сцепка|свалка

Т.е. будут рядом две вертикальные черты "||". Главное, чтобы в пределах разных строк не было повторов слов.

Зачем это все надо:
Далее этот файл поместится в БД. При выборке какого-то конкретного одного слова, база должна возвращаться одну строку.

Сейчас же из-за повторов слов в разных строках база возвращает несколько строк, в которых находит вхождение заданного слова.
11. neokiev - 01 Октября, 2015 - 10:08:32 - перейти к сообщению
А что мешает доработать скрипт который я написал выше.
используй var_dump() или xdebug и смотри где и почему слово удалилось.
И еще если вы будете использовать базу то, есть еще один вариант:
1) Можно читать из файла построчно и записывать в базу, и проверять нет ли такой записи в базе, если слово существует то не записывать, главное правильно структуру базы сделать.
12. dcc0 - 01 Октября, 2015 - 11:05:04 - перейти к сообщению
seowin, т.е. первые слова в строке всегда в алфавитном порядке? И если их 15 тыс, - они от "А" до "Я" ?
13. Deonis - 01 Октября, 2015 - 12:40:40 - перейти к сообщению
seowin, т.к. файл большой и его структура такая же, как у csv-файлов, то я бы сделал так:
PHP:
скопировать код в буфер обмена
  1. $output = [];
  2. $voc = [];
  3. if (($fp = fopen('input_file.csv', 'r')) !== false) {
  4.     while (($data = fgetcsv($fp, 1000, '|')) !== false) {
  5.         $tmp = array_diff($data, $voc);
  6.         $voc = array_merge($voc,$tmp);                         
  7.         $output[] = $tmp;
  8.     }
  9.     fclose($fp);
  10. }
  11. // записываем обработанные данные в новый файл
  12. $fp = fopen('output_file.csv', 'w');
  13. foreach ($output as $fields) {
  14.     fputcsv($fp, $fields, '|');
  15. }
  16. fclose($fp);
P.S. Расширение файла не обязательно должно быть csv
14. andrewkard - 01 Октября, 2015 - 13:55:31 - перейти к сообщению
Еще вариант Улыбка :
PHP:
скопировать код в буфер обмена
  1.  
  2. $f = fopen('1.txt','r');
  3. $arr_test = array();
  4. $str = '';
  5. while (!feof($f)) {
  6.     $line = fgets($f);
  7.     $arr_words = explode('|',$line);
  8.     foreach ($arr_words as $index => $word){
  9.         if (in_array(trim($word), $arr_test)){
  10.            $arr_words[$index] = '';
  11.         } else {
  12.             $arr_test[] = trim($word);
  13.         }
  14.     }
  15.     $str .= join('|', $arr_words);
  16. }
  17. fclose($f);
  18.  
  19. $f = fopen('2.txt','w');
  20. fwrite($f, $str);
  21. fclose($f);
  22.  
15. seowin - 01 Октября, 2015 - 14:06:33 - перейти к сообщению
Интересный способ. Большое спасибо!

Работает, как надо!

Deonis пишет:
seowin, т.к. файл большой и его структура такая же, как у csv-файлов, то я бы сделал так:
PHP:
скопировать код в буфер обмена
  1. $output = [];
  2. $voc = [];
  3. if (($fp = fopen('input_file.csv', 'r')) !== false) {
  4.     while (($data = fgetcsv($fp, 1000, '|')) !== false) {
  5.         $tmp = array_diff($data, $voc);
  6.         $voc = array_merge($voc,$tmp);                         
  7.         $output[] = $tmp;
  8.     }
  9.     fclose($fp);
  10. }
  11. // записываем обработанные данные в новый файл
  12. $fp = fopen('output_file.csv', 'w');
  13. foreach ($output as $fields) {
  14.     fputcsv($fp, $fields, '|');
  15. }
  16. fclose($fp);
P.S. Расширение файла не обязательно должно быть csv

 

Powered by ExBB FM 1.0 RC1