Как отобразить и подсчитать гласные в файле

Вопрос или проблема

У меня есть файл со списком имен, как показано ниже:

Ishmael
Mark
Anton
Rajesh
Pete

Я пытаюсь напечатать что-то вроде этого:

Iae 3
a   1
Ao  2
ae  2
ee  2

Я разработал этот код:

cat names.txt | grep -Eo '[AEIOUaeiou]' | wc -l 

но я получил в ответ общее количество гласных во всем файле. Чего не хватает в моем коде, чтобы отображать его, как показано выше?
Спасибо за вашу помощь

Как насчет

awk '{gsub (/[^AEIOUaeiou]/, ""); print $0, length}' names.txt

или (немного короче, но предполагая использование реализации GNU awk)

gawk -v IGNORECASE=1 '{gsub (/[^AEIOU]/, ""); print $0, length}' names.txt

Также у вас есть бесполезный вызов cat в вашем тестовом коде.

[EDIT] Я не видел, что ссылку предоставил Крис Дэвис. Мой ответ действительно дублирует предыдущие вопросы.

Что вы хотите сделать, это по сути удалить все, кроме гласных, и затем подсчитать количество символов в строке. Ваша попытка не удалась, потому что grep -o будет печатать каждое совпадение на отдельной строке, так что он печатал каждую гласную отдельно. Вы искали что-то вроде этого:

$ tr -dc 'AEIOUaeiou\n' < names.txt | awk '$0=$0" "length' 
Iae 3
a 1
Ao 2
ae 2
ee 2

Команда tr может trанслировать между наборами символов. С флагом -d она удаляет их, а -c делает так, чтобы она брала дополнение к тому, что вы ей дали. Таким образом, tr -dc x < file будет печатать содержимое file после удаления всех символов, кроме x. Здесь tr -dc 'AEIOUaeiou\n' удалит все, что не является гласной или символом новой строки:

$ tr -dc 'AEIOUaeiou\n' < names.txt 
Iae
a
Ao
ae
ee

Таким образом, нам просто нужно получить количество, и я использовал для этого awk.

$0 — это оператор $, примененный к числу 0, что приводит к полному текущему входному объекту (по умолчанию объекты — это строки). Для простоты можно считать $0 специальной переменной, содержащей текущую строку.

length — это функция, возвращающая длину (в символах для скаляров и по количеству элементов для массивов) того, что вы ей передаете, и если вы ей ничего не передаете, она работает с $0. Таким образом, это дает нам количество символов.

$0=$0" "length означает “добавить пробел, а затем результат length в конец строки. Наконец, в awk по умолчанию выполняется печать текущего значения $0 в случае, если что-то оценивается как истина. Из-за конкатенации строк в $0=$0" "length результат этой операции будет строкой, и строка в awk считается истинной, пока она не является пустой, что всегда будет так здесь, поэтому результирующее $0 всегда будет напечатано.

Я просто переформулирую подход doneal24 здесь, используя немного другое сочетание инструментов.

Используя Raku (ранее известный как Perl_6)

~$ raku -ne '.comb(/ :i <[aeiou]> /).list andthen put $_.join ~"\t"~ $_.chars;'  file

#ИЛИ:

~$ raku -ne 'my @a = .comb(/ :i <[aeiou]> /); put @a.join ~"\t"~ @a.chars;'  file

Пример ввода:

Ishmael
Mark
Anton
Rajesh
Pete

Пример вывода:

Iae 5
a   1
Ao  3
ae  3
ee  3

Выше мы видим действие функции comb в Raku, которую можно рассматривать как противоположность split. Ищутся определенные шаблоны, а несовпадающие шаблоны удаляются.

Это приводит нас к приятной особенности Raku, что язык готов к работе с Unicode. За исключением имен файлов, кодовые точки по умолчанию проходят нормализацию NFC. Таким образом, даже если входная строка может обозначать символ á двумя разными способами, Raku все равно будет считать его всего одним (1) символом:

~$ raku -e 'put "\c[LATIN SMALL LETTER A WITH ACUTE]";'
á
~$ raku -e 'put "\c[LATIN SMALL LETTER A]\c[COMBINING ACUTE ACCENT]";'
á
~$ raku -e 'put "\c[LATIN SMALL LETTER A WITH ACUTE]";' | raku -ne '.chars.put;'
1
~$ raku -e 'put "\c[LATIN SMALL LETTER A]\c[COMBINING ACUTE ACCENT]";' | raku -ne '.chars.put;'
1

https://docs.raku.org/language/unicode
https://raku.org

Если вы хотите сделать это на чистом bash, без запуска других программ:

while IFS= read -r line; do
  vowels="${line//[^aAeEiIoOuU]/}" # Удаляем все, кроме гласных
  echo "$vowels ${#vowels}"        # Печатаем гласные и длину
done < input.txt

Заметьте, что while read … по файлу не рекомендуется, потому что это небезопасно, медленно и не очень красиво.

С помощью perl, предполагая ввод ASCII и рассматривая только aeiouAEIOU без диакритических знаков¹ как гласные:

perl -ne '
  @vowels = /[aeiou]/gi;
  printf "%-5s %d\n", join("", @vowels), scalar@vowels' < input

Чтобы также учитывать aeiouAEIOU, когда они имеют диакритические знаки (например, é в моем имени) или встречаются в символах, таких как ℡ ℻ Ⅷ ⅲ ⒜ ㉐ ㎉ ffi 🄐 (например, в Effie), вы можете искать их как группы символов (совпадающие с \X в регулярных выражениях Perl) в их канонической декомпозиционной нормализационной форме (NFKD) с помощью чего-то вроде:

perl -C -MUnicode::Normalize=NFKD,NFKC -lne '
  @vowels = map {NFKC($_)} (NFKD($_) =~ /(?=[aeiou])\X/gi);
  printf "%-6s %d %s\n", join("", @vowels), scalar@vowels'

Которое на Henry Ⅷ, Stéphane, Effie и Louisiana дает:

eIII   4
éae    3
Eie    3
ouiiaa 6

(Никто не считает I в гласной, но опять же, в некоторых может такой произношение как в Iota / Yeti, где I или Y считаются производителями гласных звуков).

Заметьте, что точка в i не считается диакритическим знаком в данном случае, и безточечный i (ı) не будет учитываться, хотя I и İ учитываться будут (независимо от того, используется ли в регулярном выражении aeiou или AEIOU).


¹ если они не выражены с помощью комбинированных символов (обратите внимание, что в ASCII нет таких символов с комбинирующими диакритическими знаками), примененными к базовому aeiouAEIOU, в этом случае будет сообщаться только база.

.

Ответ или решение

Вопрос, поставленный в задачи, заключается в том, чтобы отобразить гласные в строках файла и подсчитать их количество, предоставляя итоговый результат в ожидаемом формате. Для решения этой задачи можно использовать различные инструменты и языки программирования. Рассмотрим несколько подходов к решению этой задачи, учитывая различные инструменты и синтаксис.

Теория

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

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

Такой алгоритм должен учитывать регистр гласных (например, ‘a’ и ‘A’ должны быть признаны гласными) и поддерживать нормализацию, если предполагается работа с символами, содержащими диакритические знаки.

Пример

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

Использование awk

awk — это мощный инструмент обработки текстов, который может использоваться для решения таких задач. Рассмотрим следующий пример на awk:

awk '{gsub (/[^AEIOUaeiou]/, ""); print $0, length}' names.txt

В этом коде:

  • gsub (/[^AEIOUaeiou]/, "") удаляет все символы, кроме гласных.
  • print $0, length выводит строку с оставшимися гласными и их количество.

Этот подход удобен, потому что awk является встроенным в большинство UNIX-систем и не требует установки дополнительных программ.

Использование tr и awk

Подход с использованием tr и awk предусматривает использование tr для фильтрации только гласных, а затем awk для подсчета:

tr -dc 'AEIOUaeiou\n' < names.txt | awk '{print $0, length}'

Команда tr -dc 'AEIOUaeiou\n' удаляет все символы, кроме гласных и перевода строки, а awk подсчитывает оставшиеся символы.

Использование bash

Возможность решения задачи с использованием скриптов на bash без обращения к внешним программам может быть реализована следующим образом:

while IFS= read -r line; do
  vowels="${line//[^aAeEiIoOuU]/}" # Удаляем все, кроме гласных
  echo "$vowels ${#vowels}"        # Выводим гласные и их количество
done < input.txt

Этот код:

  • Позволяет прочитать каждую строку файла.
  • Использует параметрическое расширение ${line//[^aAeEiIoOuU]/} для фильтрации гласных.
  • Выводит гласные и их количество.

Применение

На практике использование того или иного инструмента зависит от конкретной задачи, требований к среде выполнения, и предпочтений разработчика. Для быстрого скриптинга и сред с ограниченными ресурсами awk и bash могут быть предпочтительными благодаря своей легкости и простоте. Если требуется более сложная обработка данных, поддержка Unicode и нормализация, такие языки как Perl или Raku могут предоставить необходимые возможности.

Пример на Perl с поддержкой Unicode

Если необходимо учитывать символы с диакритическими знаками, можно использовать Perl с поддержкой Unicode:

perl -C -MUnicode::Normalize=NFKD,NFKC -lne '
  @vowels = map {NFKC($_)} (NFKD($_) =~ /(?=[aeiou])\X/gi);
  printf "%-6s %d\n", join("", @vowels), scalar@vowels' < input.txt

Этот код:

  • Поддерживает нормализацию Unicode.
  • Учитывает комбинированные символы.

Эти подходы показывают гибкость и разнообразие методов для решения задачи отображения и подсчёта гласных в строках файла. Выбор инструмента зависит от потребностей конкретного проекта и других факторов, таких как совместимость и производительность.

Оцените материал
Добавить комментарий

Капча загружается...