Как удалить дублирующиеся буквы с помощью sed?

Не используя дополнительные уровни безопасности как SELinux, Вы не можете сделать этого. Но затем это - плохая идея также, так как существует действительно много других возможностей заблокировать другого пользователя, если можно стать (почти сытыми) корневые права через sudo.

См. https://serverfault.com/questions/36759/editing-sudoers-file-to-restrict-a-users-commands

6
11.09.2013, 01:47
7 ответов

Метод № 1

Можно использовать это sed команда, чтобы сделать это:

$ sed 's/\([A-Za-z]\)\1\+/\1/g' file.txt

Пример

Используя Ваш выше демонстрационного входа я создал файл, sample.txt.

$ sed 's/\([A-Za-z]\)\1\+/\1/g' sample.txt 
NAME
       nice - run a program with modified scheduling priority

       SYNOPSIS
              nice     [-n    adjustment]    [-adjustment] [--adjustment=adjustment] [command [a$

Метод № 2

Существует также этот метод, который удалит все дублирующиеся символы:

$ sed 's/\(.\)\1/\1/g' file.txt 

Пример

$ sed 's/\(.\)\1/\1/g' sample.txt 
NAME
    nice - run a program with modified scheduling priority

    SYNOPSIS
       nice   [-n  adjustment]  [-adjustment] [-adjustment=adjustment] [command [a$

Метод № 3 (просто верхний регистр)

OP, который спрашивают, если бы Вы могли бы изменить его так, чтобы только символы верхнего регистра были бы удалены, вот то, как с помощью измененного метода № 1.

Пример

$ sed 's/\([A-Z]\)\1\+/\1/g' sample.txt 
NAME
       nice - run a program with modified scheduling priority

       SYNOPSIS
              nice     [-n    adjustment]    [-adjustment] [--adjustment=adjustment] [command [a$

Детали вышеупомянутых методов

Все примеры используют технику, где, когда с символом сначала встречаются, это находится в наборе символов A-Z или a-z, что это - значение, сохраняется. Обертывание parens вокруг символов говорит sed сохранить их на потом. То значение затем хранится во временной переменной, к которой можно получить доступ или сразу или позже. Эти переменные называют \1 и \2.

Таким образом, прием, который мы используем, мы соответствуем первой букве.

\([A-Za-z]\)

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

\([A-Za-z]\)\1.

В sed мы также используем поиск и заменяем средство, s/../../g. g средства мы делаем его глобально.

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

10
27.01.2020, 20:22
  • 1
    . Rremoving все дубликаты не то, что я хочу сделать; например, "команда" должна остаться "команда", но "NNAAMMEE" должен стать "ИМЕНЕМ", там способ использовать sed с / (.)\1/\1/g', но только для двойных прописных букв? –   11.09.2013, 02:43
  • 2
    @JonSmith - Вы могли взять первый пример и удалить бит a-z из набора символов. sed 's/\([A-Z]\)\1\+/\1/g' –  slm♦ 11.09.2013, 02:45
  • 3
    Чтобы сделать это в просто заголовках, добавить /^[A-Z]/ - sed '/^[A-Z]/s/\(.\)\1/\1/g' –  Kevin 11.09.2013, 04:28
  • 4
    Можно ли объяснить, для чего круглой скобки? Как [A-Z] отличающийся от ([A-Z]) кроме того, для чего + оператор? Эти \1 для сопоставления с образцом, корректного? –   11.09.2013, 08:26
  • 5
    @slm, из которого я знал только основной sed, этот ответ удивителен, но можете Вы объяснять. как то, что означает \1 –  Rahul Patil 12.09.2013, 19:13

Эта команда удаляет все двойные буквы:

sed 's/\([[:alpha:]]\)\1/\1/g'

\1 обозначает текст внутри \(…\), так это средство команды: везде, где существует алфавитный символ, сопровождаемый отдельно, замена одним только тем алфавитным символом.

Это преобразует, например. command в comand. Было бы лучше ограничить преобразование туда, где это необходимо: строки нес отступом.

sed '/^[[:alpha:]]/ s/\([[:alpha:]]\)\1/\1/g'

Этот текст является страницей справочника, представленной для терминалов, где полужирный представлен наложением: C\bC представляется как полужирный, где \b символ возврата (число символов 8, также известный как ^H). Если управляющие символы все еще там, забывают о дублирующихся буквах и вместо этого удаляют наложение.

sed -e 's/.\b//g'

Если у Вас есть способ отформатировать вывод, transofmr C\bC к полужирному и _\bC подчеркнуть.

sed -e 's/\(.\)\b\1/\e[1m\1\e[22m/g' -e 's/_\b\(.\)/\e[4m\1\e[24m/g' |
sed -e 's/\e[22m\e[1m//g' -e 's/\e[24m\e[4m//g'

Если Ваш sed не понимает Escape обратной косой черты, используйте буквенные символы (Ctrl+H для \b и Ctrl + [для \e).

3
27.01.2020, 20:22

Это ни в коем случае не тривиальная задача. Простая замена на букву удваивается, имело бы катастрофические последствия. Думайте о том, что это сделало бы к словам как "внимание" или "упущение" или (более относящийся к Вашему случаю) "команда". Сценарий ниже является наивной первой попыткой в решении. Это использует словарь для определения, какие слова действительно имеют дублирующиеся буквы.

#!/usr/bin/perl

use strict;
use warnings;

my $input_file = shift//die "No file name given\n";
my $dictionary = shift//'/usr/share/dict/words';
open my $if,'<',$input_file or die "$input_file: $!\n";
open my $dict,'<',$dictionary or die "$dictionary: $!\n";
my %dictionary;
for(<$dict>){
    chomp;
    $dictionary{$_}++;
}
close $dictionary;

LINE: while(<$if>){
    chomp;

    WORD: for my $word ( split /\s+/ ){
            print "$word " and next WORD if exists $dictionary{lc $word};

            SUBSTITUTION: while($word=~ s{([A-Z])\1}{$1}i){
                exists $dictionary{lc $word} and last SUBSTITUTION;
            } #END SUBSTITUTION
            print "$word ";

     } #END WORD

     print "\n";

} #END LINE

Назовите его как

[user@host]./myscript.pl input_file optional_dictionary_file >output_file

Если Вы не предоставляете второй аргумент, значения по умолчанию файла словаря к /usr/share/dict/words, который должен быть доступным на достойном GNU/Linux.

Отказ от ответственности: Это не тестируется.

Протесты:

  • Это повредится, по крайней мере, с написанными через дефис словами (это использует пробелы для решения то, что "слово").
  • Это только удалит дублированные прописные буквы, чтобы не смешивать с содержанием man страница самостоятельно.
  • Это нанесет ущерб hexadecimals как 0xFFFF.
  • Вероятно, намного больше то, что я не вижу.
2
27.01.2020, 20:22
  • 1
    , я соглашаюсь, что удаление всех дубликатов не то, что я хочу сделать; например, "команды" должны остаться "команды", но "NNAAMMEE" должен стать "ИМЕНЕМ" спасибо –   11.09.2013, 02:42
  • 2
    @JonSmith... и что должно заголовок SSHHEELLLL GGRRAAMMMMAARR (от, предположительно, поврежденной страницы удара человека), становятся? –  Joseph R. 11.09.2013, 04:03

Можно ограничить изменения в затронутых строках с чем-то вроде этого:

eval sed $(
for i in NAME SYNOPSIS DESCRIPTION "RETURN VALUE" ENVIRONMENT FILES EXAMPLES DIAGNOSTICS ERRORS "SEE ALSO" "CONFORMING TO" HISTORY AUTHORS BUGS; do
  dup=$(for j in $(seq 0 ${#i}); do printf "%s%s" "${i:j:1}" "${i:j:1}"; done)
  printf " -e \"s/%s/%s/\"" "$dup" "$i"
done)
0
27.01.2020, 20:22

В Python:

Метод 1# Используя собственную функцию:

#!/usr/bin/env python
from __future__ import print_function
import sys

def RemoveDupliChar(Word):
        NewWord = " "
        index = 0
        for char in Word:
               if char != NewWord[index]:
                       NewWord += char
                       index += 1
        print(NewWord.strip())

with open(sys.argv[1],'r') as InputFile:
        for line in InputFile:
                if line.isupper():
                        RemoveDupliChar(line)
                else:
                        print(line,end='')

Метод 2# Используя itertools.groupby:

Благодаря @falstretu

#!/usr/bin/env python
from __future__ import print_function
import itertools
import sys

with open(sys.argv[1],'r') as InputFile:
        for line in InputFile:
                if line.isupper():
                        print(''.join(ch for ch, _ in itertools.groupby(line)))
                else:
                        print(line,end='')

Выполнение:

root@ubuntu:~# python remove_duplicate_char.py Input.txt
NAME
       nice - run a program with modified scheduling priority

SYNOPSIS
       nice     [-n    adjustment]    [-adjustment]    [--adjustment=adjustment] [command [a$
0
27.01.2020, 20:22

Кажется, ваш пример взят из страниц руководства.

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

vi может легко удалить их.

См .: https://stackoverflow.com/questions/26634497/redirecting-man-page-output-to-file-results-in-double-letters-in-words

1
27.01.2020, 20:22

Попробуйте:

sed -e 's/\([A-Za-z]\)\1/\1/g'  

Просто удалите \\\+, тогда только удвоенные буквы сократятся до одной. (Работает при условии, что все символы были продублированы)

Попробуйте этот небольшой тест:

echo "PPaayy Atttteenttiioonn ttoo aallll ccoommmmaanndds" > test.txt
sed -e 's/\([A-z]\)\1/\1/g' < test.txt > test2.txt
cat test2.txt
0
27.01.2020, 20:22

Теги

Похожие вопросы