LINUX.ORG.RU

Срезать окончания слов где нужно и сохранить

 ,


2

1

Всем Доброго времени суток!

Есть файл со словами, word.txt, (слова написаны в столбик, по 1 слову на строке). Есть файл numbers.txt, содержащий числа (разные, в диапазоне от 1 до 23, тоже по одному числу на строку). Количество слов/строк в words.txt соответствует таковому в numbers.txt. Необходимо у слов в words.txt обрезать окончания, по принципу «число из numbers.txt показывает число букв, которое должно остаться после обрезания». Также нужно отдельно сохранить слова, в которых обрезания не потребовалось (число из numbers равно числу букв слова). Файлы имеют около 100тыс. строк.

Как составить файл паттернов для sed?

Не буду настаивать, что моё решение самое красивое или эффективное, но, например, можно как-то так:

#!/bin/bash

rm -f [ab].txt

cat num.txt | awk '{print NR " " $0}' > num1.txt

cat nam.txt | awk '{print NR " " $0}' > nam1.txt

join -j1 nam1.txt num1.txt | sed 's/^[0-9]* //' | awk '{print "if [ `echo -n " $1 " | wc -c` -le " $2 " ]; then echo " $1 " >> b.txt; echo " $1 " >> a.txt; else echo " $1 " | sed \"s/\\\(.*\\\)\\\(.\\{" $2 "\\}$\\\)/\\1/\" >> a.txt; fi; "}' 2> /dev/null > nam_num.sh

bash nam_num.sh


# Это вывод на экран, его можно удалить:

echo a.txt:

cat a.txt

echo b.txt:

cat b.txt

Сначала мы нумеруем строки, потом объединяем файлы по номерам строк, одновременно удаляя эти номера, потом генерим скрипт и запускаем его. Предполагается, что имена файлов не содержат пробелов. Если это не так, то тоже поправимо, но скрипт чуток усложнится (сначала надо будет заменить все пробелы на символ, который гарантированно не встречается, командой tr, например, а потом той же командой вернуть пробелы).

В файл b.txt пишутся не модифицировавшиеся имена, в файл a.txt - все имена. Если надо писать только модифицированные, достаточно удалить из самой длинной строчки внутри if'а «echo » $1 " >> a.txt;"

aureliano15 ★★
()
#!/bin/bash

seq 10 | awk '{
  word = word $0
  printf "%i\n", word > "word.txt"
  printf "%i\n", 11-$0 > "num.txt"
}'

awk '{
  getline n < "num.txt"
  print substr($0, 0, n)
}' word.txt
anonymous
()
Ответ на: комментарий от anonymous

Кстати да, я невнимательно прочёл и не оставил число букв, записанных в num, а наоборот обрезал это число букв справа. Да и вообще этот вариант лучше, правда не сохраняет отдельно необрезанные слова, но это вообще пустяк. :-)

aureliano15 ★★
()
Ответ на: комментарий от mix_mix

Не щупал 3-й питон. open(file) возвращает итератор а не файловый дкскриптор?

Deleted
()
Ответ на: комментарий от Deleted

По-моему по нынешним временам это не так много. 100000 имён * не более 23 букв в имени <= 2.3 метра. При объёмах ОЗУ минимум 1 Гб. (это если очень скромненькая техника) сущие копейки. :-)

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

Пустяк. Если уникод, то в два(хз) раза больше. А если логи увеличатся, то и еще. Канеш, есть задачи где скриптами лучше использовать более быструю память. А есть задачи, где нет в этом необходимости. Полезно помнить, что скрипты запускаются с уже работающими плеерами, браузерами, мессенджерами, ДЕ, в виртуалках, и т.д.

Deleted
()
Ответ на: комментарий от Deleted

Это да. Но в данном случае речь не о каком-то мощном ПО на все случае жизни, а о скрипте на 2-3 строчки для конкретной задачи на конкретной машине. Если данные разрастутся или память резко уменьшится (в какой-нить виртуалке), всегда можно будет переписать. :-) Хотя в общем случае согласен.

aureliano15 ★★
()
Ответ на: комментарий от anonymous

Спасибо за помощь, но похоже что-то не то, - после выполнения этого скрипта, word.txt превратился в

1
12
123
1234
12345
123456
1234567
12345678
123456789
12345678910
а num.txt превратился в
10
9
8
7
6
5
4
3
2
1

И вообще-то желательно, чтобы обрезанные слова сохранились отдельно, необрезанные отдельно.

sspphheerraa
() автор топика
Ответ на: комментарий от sspphheerraa

Я искренне желал вам помочь, но не давал готового решения, только пытался направить вас в нужном направлении. Что случилось с word.txt и num.txt описано в первом awk того скрипта. Это было просто создание примера для работы следующего за ним скрипта.

anonymous
()
Ответ на: комментарий от anonymous

Вышеприведенный скрипт на питоне тоже не делает желаемое. К сожалению, я не знаток программирования. Но мне кажется, что задачу можно сделать путём cat/cut, что-то типа

$ cat word.txt | cut -c 1-20
где вместо 20, как-то бы надо подставлять для каждой строчки своё число...

sspphheerraa
() автор топика
#!/usr/bin/env ruby

words = IO.read('words').split("\n")
nums = IO.read('nums').split("\n").map(&:to_i)

full_words = File.open('full_words.txt', 'w')
cuted_words = File.open('cuted_words.txt', 'w')

words.each_with_index do |word, n|
  puts new_word = word[0...nums[n]]
  if new_word == word
    full_words.puts new_word
  else
    cuted_words.puts new_word
  end
end

TDrive ★★★★★
()
Последнее исправление: TDrive (всего исправлений: 1)
Ответ на: комментарий от sspphheerraa

где вместо 20, как-то бы надо подставлять для каждой строчки своё число...

это и делает тот скрипт

anonymous
()
Ответ на: комментарий от sspphheerraa

и опять же, я только пытаюсь вам помочь, попробуйте приложить усилия и тогда, если у вас не будет получаться, я смогу вам помочь.

anonymous
()
$ perl -E 'open $_,shift for F1,F2; for(;;){ chomp($x=<F1>,$y=<F2>); $x && $y or last; say substr $x,$y*-1 }' words.txt numbers.txt

если правильно понял.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

а, сохранять...

$ perl -E 'open $_,shift for F1,F2; for(;;){ chomp($x=<F1>,$y=<F2>); $x && $y or last; $W=length($s=substr $x,$y*-1) == length $x ? STDERR : STDOUT; say $W $s }' words.txt numbers.txt 1>cuted 2>full

так-то.

Deleted
()
Ответ на: комментарий от anonymous

чтоб в alias/функцию можно было закинуть. Можно и в скрипт, по желанию.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от TDrive

TDrive, дай вам Бог здоровья, добрый человек. Это то, что надо.

sspphheerraa
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.