Как найти уникальные символы в строке ввода?
есть ли способ извлечь уникальные символы каждой строки?
Я знаю, что я могу найти уникальные строки файла, используя
sort -u file
Я хотел бы определить уникальные символы каждой строки (что-то вроде sort -u
для каждой линии).
чтобы уточнить: учитывая этот ввод:
111223234213
111111111111
123123123213
121212122212
Я хотел бы получить этот вывод:
1234
1
123
12
7 ответов
использование sed
sed ':;s/\(.\)\(.*\)//;t' file
в основном то, что он делает, это захватить символ и проверить, появляется ли он в другом месте на линии. Он также захватывает все символы между ними. Затем он заменяет все это, включая второе явление, только первым явлением, а затем тем, что было между ними.
t
является тестом и переходит к :
метка, если предыдущая команда была успешной. Затем это повторяется до s///
команда не работает, что означает только уникальные символы оставаться.
;
просто отделяет команды.
1234
1
123
12
поддерживает порядок, а также.
он не получает вещи в исходном порядке, но этот awk one-liner, кажется, работает:
awk '{for(i=1;i<=length();i++){a[substr(,i,1)]=1} for(i in a){printf("%s",i)} print "";delete a}' input.txt
разделить на части для облегчения чтения, это может быть автономным, как это:
#!/usr/bin/awk -f
{
# Step through the line, assigning each character as a key.
# Repeated keys overwrite each other.
for(i=1;i<=length();i++) {
a[substr(,i,1)]=1;
}
# Print items in the array.
for(i in a) {
printf("%s",i);
}
# Print a newline after we've gone through our items.
print "";
# Get ready for the next line.
delete a;
}
конечно, та же концепция может быть реализована довольно легко и в pure bash:
#!/usr/bin/env bash
while read s; do
declare -A a
while [ -n "$s" ]; do
a[${s:0:1}]=1
s=${s:1}
done
printf "%s" "${!a[@]}"
echo ""
unset a
done < input.txt
обратите внимание, что это зависит от bash 4, из-за ассоциативного массива. А этот! .. --14-->тут получить вещи в исходном порядке, потому что bash делает лучшую работу держать ключи в порядке, чем на awk.
и я думаю, что у вас есть решение с помощью sed
от Хосе, хотя у него есть куча дополнительных фитингов. :)
последний инструмент, который вы упомянули grep
. Я уверен, что вы не можете сделать это в традиционном grep, но, возможно, какая-то храбрая душа сможет построить вариант perl-regexp (т. е. grep -P
) через -o
и lookarounds. Им нужно больше кофе, чем во мне сейчас.
один из способов, используя perl:
perl -F -lane 'print do { my %seen; grep { !$seen{$_}++ } @F }' file
результаты:
1234
1
123
12
другое решение,
while read line; do
grep -o . <<< $line | sort -u | paste -s -d '' -;
done < file
grep -o .
преобразовать 'row line' в 'column line'sort -u
сортировка писем и удалить repetead буквыpaste -s -d '' -
преобразовать 'column line' в 'row line'-
в качестве аргумента имени файла для вставки, чтобы сказать ему использовать стандартный ввод.
этот awk должен работать:
awk -F '' '{delete a; for(i=1; i<=NF; i++) a[$i]; for (j in a) printf "%s", j; print ""}' file
1234
1
123
12
здесь:
-F ''
побьет рекорд char по char, давая нам один символ в ,
etc.
Примечание: для использования без gnu awk:
awk 'BEGIN{FS=""} {delete a; for(i=1; i<=NF; i++) a[$i];
for (j in a) printf "%s", j; print ""}' file
Это может сработать для вас (GNU sed):
sed 's/\B/\n/g;s/.*/echo "&"|sort -u/e;s/\n//g' file
разбить каждую строку на ряд строк. Уникальная сортировка этих строк. Объедините результат в одну строку.
уникальная и отсортированная альтернатива другим, используя инструменты sed и gnu:
sed 's/\(.\)/\n/g' file | sort | uniq
который производит один символ на строку; если вы хотите, чтобы они были на одной строке, просто сделайте:
sed 's/\(.\)/\n/g' file | sort | uniq | sed ':a;N;$!ba;s/\n//g;'
это имеет то преимущество, что символы отображаются в отсортированном порядке, а не в порядке появления.