Как можно добавить инкрементный счетчик к каждому предопределенному слову текстового файла?
Как и этот вопрос: Как добавить инкрементный счетчик к каждой строке текстового файла?
Я хочу добавить инкрементный счетчик в текстовый файл. Но вместо добавления инкрементного счетчика к каждой строке, я хотел бы добавить инкрементный счетчик к предопределенному слову.
Например, если я хочу подсчитать количество слов «кино» в тексте, я бы хотел, чтобы все упоминания слова «кино» были заменены на «киноN», где N — это порядковый номер, а максимальное значение N зависит от того, сколько раз слово «кино» встречается в тексте.
Итак, входной текстовый файл, содержащий этот текст:
Он подъехал на своей машине к кинотеатру. Затем он зашел в кинотеатр, чтобы купить билеты, и обнаружил, что прошло уже больше двух лет с тех пор, как он последний раз был там.
Создает выходной файл со следующим содержимым:
Он поехал на своей машине в кинотеатр1. Затем он зашел в кинотеатр2, чтобы купить билеты, и впоследствии обнаружил, что прошло уже более двух лет с тех пор, как он последний раз был в кинотеатре3.
Желательно также иметь возможность нумеровать выбранные слова в обратном порядке.
Т.е. это сгенерирует второй выходной файл с таким содержимым:
Он поехал на своей машине в кинотеатр3. Затем он зашел в кинотеатр2, чтобы купить билеты, и обнаружил, что прошло уже больше двух лет с тех пор, как он последний раз был в кинотеатре1.
решение1
Я бы предпочел perl
для этого:
$ cat ip.txt
He drove his car to the cinema. He then went inside the cinema to purchase tickets, and afterwards discovered that it was more then two years since he last visited the cinema.
$ # forward counting is easy
$ perl -pe 's/\bcinema\b/$&.++$i/ge' ip.txt
He drove his car to the cinema1. He then went inside the cinema2 to purchase tickets, and afterwards discovered that it was more then two years since he last visited the cinema3.
\bcinema\b
слово для поиска, используя границы слов, чтобы оно не совпадало как частичная часть другого слова. Например,\bpar\b
не будет соответствоватьapart
илиpark
илиspar
ge
флагg
предназначен для глобальной замены.e
позволяет использовать код Perl в разделе замены$&.++$i
представляет собой конкатенацию совпавшего слова и предварительно увеличенного значения,$i
которое имеет значение по умолчанию0
Для обратного нам сначала нужно получить количество...
$ c=$(grep -ow 'cinema' ip.txt | wc -l) perl -pe 's/\bcinema\b/$&.$ENV{c}--/ge' ip.txt
He drove his car to the cinema3. He then went inside the cinema2 to purchase tickets, and afterwards discovered that it was more then two years since he last visited the cinema1.
c
становится переменной окружения, доступной через хэш%ENV
или, в perl
одиночку, прихлебывая весь файл
perl -0777 -pe '$c=()=/\bcinema\b/g; s//$&.$c--/ge' ip.txt
решение2
С GNU awk для многосимвольного RS, совпадения без учета регистра и границ слов:
$ awk -v RS='^$' -v ORS= -v word='cinema' '
BEGIN { IGNORECASE=1 }
{ cnt=gsub("\\<"word"\\>","&"); while (sub("\\<"word"\\>","&"cnt--)); print }
' file
He drove his car to the cinema3. He then went inside the cinema2 to purchase tickets, and afterwards discovered that it was more then two years since he last visited the cinema1.
решение3
С учетом знаков препинания после слова.
Прямая нумерация:
word="cinema"
awk -v word="$word" '
{
for (i = 1; i <= NF; i++)
if ($i ~ word "([,.;:)]|$)") {
gsub(word, word "" ++count,$i)
}
print
}' input-file
Обратная нумерация:
word="cinema"
count="$(awk -v word="$word" '
{ count += gsub(word, "") }
END { print count }' input-file)"
awk -v word="$word" -v count="$count" '
{
for (i = 1; i <= NF; i++)
if ($i ~ word "([,.;:)]|$)") {
gsub(word, word "" count--, $i)
}
print
}' input-file
решение4
Для разметки слова в порядке убывания мы инвертируем регулярное выражение И инвертируем данные, а затем инвертируем дату еще раз, чтобы осуществить преобразование:
perl -l -0777pe '$_ = reverse reverse =~ s/(?=\bamenic\b)/++$a/gre' input.data
Результат
He drove his car to the cinema3. He then went inside the cinema2 to purchase tickets, and
afterwards discovered that it was more then two years since he last visited the cinema1.
Для маркировки слова в порядке возрастания мы выполняем ретроспективный поиск слова:
perl -lpe 's/\bcinema\b\K/++$a/eg' input.data
Результат
He drove his car to the cinema1. He then went inside the cinema2 to purchase tickets, and
afterwards discovered that it was more then two years since he last visited the cinema3.