Вопрос или проблема
У меня есть файл со списком имен, как показано ниже:
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
Если вы хотите сделать это на чистом 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, в этом случае будет сообщаться только база.
.
Ответ или решение
Вопрос, поставленный в задачи, заключается в том, чтобы отобразить гласные в строках файла и подсчитать их количество, предоставляя итоговый результат в ожидаемом формате. Для решения этой задачи можно использовать различные инструменты и языки программирования. Рассмотрим несколько подходов к решению этой задачи, учитывая различные инструменты и синтаксис.
Теория
Для решения задачи по отображению и подсчету гласных в строках из файла необходимо разработать алгоритм, который выполняет несколько ключевых шагов:
- Чтение файла: Необходимо открыть файл и прочитать его содержимое построчно.
- Обработка строк: Для каждой строки файла требуется определить, какие символы являются гласными.
- Подсчет и отображение: После определения гласных потребуется подсчитать их количество в каждой строке и вывести результат в требуемом формате.
Такой алгоритм должен учитывать регистр гласных (например, ‘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.
- Учитывает комбинированные символы.
Эти подходы показывают гибкость и разнообразие методов для решения задачи отображения и подсчёта гласных в строках файла. Выбор инструмента зависит от потребностей конкретного проекта и других факторов, таких как совместимость и производительность.