Определить дубликаты строк в файле, не удаляя их?

string? wstring?

std::string basic_string шаблонные на char, и std::wstring на wchar_t .

char по сравнению с [1 110]

char, как предполагается, содержит символ, обычно 8-разрядный символ.
wchar_t, как предполагается, содержит широкий символ, и затем, вещи становятся хитрыми:
На Linux, wchar_t 4 байта, в то время как в Windows, это - 2 байта.

Что относительно [1 149] Unicode, тогда?

проблема состоит в том, что ни char, ни wchar_t непосредственно связывается с unicode.

На Linux?

Позволяют нам взять ОС Linux: Моя система Ubuntu уже unicode знающая. Когда я работаю с символьной строкой, она исходно кодируется в [1 150] UTF-8 (т.е. строка Unicode символов). Следующий код:

#include 
#include 

int main(int argc, char* argv[])
{
   const char text[] = "olé" ;


   std::cout << "sizeof(char)    : " << sizeof(char) << std::endl ;
   std::cout << "text            : " << text << std::endl ;
   std::cout << "sizeof(text)    : " << sizeof(text) << std::endl ;
   std::cout << "strlen(text)    : " << strlen(text) << std::endl ;

   std::cout << "text(ordinals)  :" ;

   for(size_t i = 0, iMax = strlen(text); i < iMax; ++i)
   {
      std::cout << " " << static_cast(
                              static_cast(text[i])
                          );
   }

   std::cout << std::endl << std::endl ;

   // - - - 

   const wchar_t wtext[] = L"olé" ;

   std::cout << "sizeof(wchar_t) : " << sizeof(wchar_t) << std::endl ;
   //std::cout << "wtext           : " << wtext << std::endl ; <- error
   std::cout << "wtext           : UNABLE TO CONVERT NATIVELY." << std::endl ;
   std::wcout << L"wtext           : " << wtext << std::endl;

   std::cout << "sizeof(wtext)   : " << sizeof(wtext) << std::endl ;
   std::cout << "wcslen(wtext)   : " << wcslen(wtext) << std::endl ;

   std::cout << "wtext(ordinals) :" ;

   for(size_t i = 0, iMax = wcslen(wtext); i < iMax; ++i)
   {
      std::cout << " " << static_cast(
                              static_cast(wtext[i])
                              );
   }

   std::cout << std::endl << std::endl ;

   return 0;
}

выводы следующий текст:

sizeof(char)    : 1
text            : olé
sizeof(text)    : 5
strlen(text)    : 4
text(ordinals)  : 111 108 195 169

sizeof(wchar_t) : 4
wtext           : UNABLE TO CONVERT NATIVELY.
wtext           : ol�
sizeof(wtext)   : 16
wcslen(wtext)   : 3
wtext(ordinals) : 111 108 233

Вы будете видеть, что "olГ©" текст в [1 116] действительно создается четырьмя символами: 110, 108, 195 и 169 (не подсчет конечного нуля). (Я позволю Вам учиться эти wchar_t код как осуществление)

Так, при работе с char на Linux, необходимо обычно заканчивать тем, что использовали Unicode, даже не зная это. И как [1 119] работы с [1 120], таким образом std::string уже unicode-готово.

Примечание, что std::string, как API струны до, будет полагать, что строка "olГ©" имеет 4 символа, не три. Таким образом, необходимо быть осторожными при усечении/игре с unicode символами, потому что некоторая комбинация символов запрещается в UTF-8.

В Windows?

В Windows, это несколько отличается. Win32 должен был поддержать много приложения, работающего с [1 123] и на различном наборы символов / кодовые страницы произведенный во всем мире перед появлением Unicode.

, Таким образом, их решением было интересное: Если приложение работает с [1 124], то символьные строки закодированы/распечатаны/показаны на маркировках GUI с помощью локального набора символов/кодовой страницы на машине. Например, "olГ©" был бы "olГ©" в локализованном французами Windows, но будет чем-то другим в локализованном кириллицей Windows ("olР№", если Вы используете Windows 1251 ). Таким образом, "исторические приложения" будут обычно все еще работать тот же старый путь.

Для основанных на Unicode приложений, использование Windows wchar_t, который 2 байта шириной, и кодируется в [1 154] UTF-16, который является Unicode, закодированным на 2-байтовых символах (или по крайней мере, главным образом совместимый UCS-2, который является почти тем же самым IIRC).

Приложения с помощью [1 126] сказаны "многобайтовые" (потому что каждый глиф состоит из одного или нескольких char с, в то время как приложения с помощью [1 128] сказаны "widechar" (потому что каждый глиф состоит из один или два wchar_t. См. MultiByteToWideChar и API WideCharToMultiByte Win32 преобразования для большего количества информации

Таким образом, если Вы работаете над Windows, Вы плохо хотите использовать wchar_t (если Вы не используете платформу, скрывающую это, как [1 157] GTK + или QT...). Факт - то, что негласно, работы Windows с [1 131] строки, поэтому даже историческим приложениям преобразуют их char строки в [1 133] при использовании API как [1 134] (низкоуровневая API-функция для установки маркирования на Win32 GUI).

Проблемы памяти?

UTF-32 составляет 4 байта на символы, таким образом, существует не очень для добавления, если только, что текст UTF-8 и текст UTF-16 будут всегда использовать меньше или тот же объем памяти, чем текст UTF-32 (и обычно меньше).

, Если существует проблема памяти, то необходимо знать, чем для большинства западных языков, текст UTF-8 будет использовать меньше памяти, чем тот же UTF-16 один.

однако, для других языков (китайский язык, японский язык, и т.д.), используемая память будет или тем же, или немного больше для UTF-8, чем для UTF-16.

, В целом, UTF-16 будет главным образом использовать 2 и иногда 4 байта на символы (если Вы не будете иметь дело с некоторыми тайными глифами языка (Klingon? Волшебный?), в то время как UTF-8 потратит от 1 до 4 байтов.

Видят http://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16 для большего количества информации

Заключение

  1. , Когда я должен использовать станд.:: wstring по станд.:: строка?

    На Linux? Почти никогда (В§).
    В Windows? Почти всегда (В§).
    На межплатформенном коде? Зависит от Вашего инструментария...

    (В§): если Вы не используете инструментарий/платформу, говорящий иначе

  2. , Может std::string содержать весь набор символов ASCII включая специальные символы?

    Уведомление: std::string подходит для содержания 'двоичного' буфера, где std::wstring не!

    На Linux? Да.
    В Windows? Только специальные символы, доступные для текущей локали пользователя Windows.

    Редактирование (После комментария от [1 160] Johann Gerell ):
    std::string будет достаточно для обработки всего char - базирующиеся строки (каждый char являющийся числом от 0 до 255). Но:

    1. ASCII, как предполагается, идет от 0 до 127. Выше char с НЕ являются ASCII.
    2. char от 0 до 127 будет сохранен правильно
    3. char от 128 до 255, будет иметь значение в зависимости от Вашего кодирования (unicode, non-unicode, и т.д.), но оно будет в состоянии содержать все глифы Unicode, пока они кодируются в UTF-8.
  3. std::wstring поддерживаются почти всеми популярными компиляторами C++?

    Главным образом, за исключением GCC основывал компиляторы, которые портированы к Windows.
    Это работает над моим g ++ 4.3.2 (в соответствии с Linux), и я использовал API Unicode на Win32 начиная с Visual C++ 6.

  4. , Что такое точно широкий символ?

    На C/C++, это - тип символов, записанный wchar_t, который больше, чем простое char тип символов. Это, как предполагается, используется для вставления символов, индексы которых (как глифы Unicode) больше, чем 255 (или 127, завися...).

11
задан 16.05.2020, 09:50

6 ответов

Если я понимаю Ваш вопрос, я думаю, что Вам нужно что-то как:

for dup in $(sort -k1,1 -u file.txt | cut -d' ' -f1); do grep -n -- "$dup" file.txt; done

или:

for dup in $(cut -d " " -f1 file.txt | uniq -d); do grep -n -- "$dup" file.txt; done

, где file.txt Ваш файл, содержащий данные о Вас, интересно.

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

8
ответ дан 16.05.2020, 09:50
  • 1
    Спасибо: даже cut -d " " -f1 file.txt | uniq -d дает мне хороший вывод. – Thảo Frederic 16.05.2020, 09:51
  • 2
    Спасибо. Вторая команда является той, которую я люблю. Можно удалить первое. И если бы Вы объясняете код, который был бы хорош также:) – Daniel Persson 16.05.2020, 09:52
  • 3
    @DKBose Там являются, вероятно, большим количеством возможностей, но я хотел использовать и Ваша команда также. – jk7 16.05.2020, 09:52

Это - классическая проблема, которая может быть решена с эти uniq команда. uniq может обнаружить дубликат последовательный строки и удалить дубликаты (-u, --unique) или сохранить дубликаты только (-d, --repeated).

Начиная с упорядочивания дублирующихся строк не важно для Вас, необходимо отсортировать его сначала. Тогда используйте uniq для печати уникальных строк только:

sort yourfile.txt | uniq -u

существует также -c опция (--count), которая печатает количество дубликатов для -d опция. См. страницу руководства uniq для деталей.

<час>

, Если Вы действительно не заботитесь о частях после первого поля, можно использовать следующую команду для нахождения, делают дубликаты ключа и печатают каждый номер строки для него (добавьте другой | sort -n, чтобы отсортировать вывод с методической точностью):

 cut -d ' ' -f1 .bash_history | nl | sort -k2 | uniq -s8 -D
<час>

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

Вот сценарий AWK (сохраните его к [1 116]), который берет Ваш текстовый файл в качестве входа и печатает все дублирующиеся строки, таким образом, можно решить, чтобы удалить. (awk -f script.awk yourfile.txt)

#!/usr/bin/awk -f
{
    # Store the line ([112]) grouped per URL ($1) with line number (NR) as key
    lines[$1][NR] = [112];
}
END {
    for (url in lines) {
        # find lines that have the URL occur multiple times
        if (length(lines[url]) > 1) {
            for (lineno in lines[url]) {
                # Print duplicate line for decision purposes
                print lines[url][lineno];
                # Alternative: print line number and line
                #print lineno, lines[url][lineno];
            }
        }
    }
}
10
ответ дан 16.05.2020, 09:51

Посмотрите следующий отсортированный file.txt:

addons.mozilla.org/en-US/firefox/addon/click-to-play-per-element/ ::: C2P per-element
addons.mozilla.org/en-us/firefox/addon/prospector-oneLiner/ ::: OneLiner
askubuntu.com/q/21033 ::: What is the difference between gksudo and gksu?
askubuntu.com/q/21148 ::: openoffice calc sheet tabs (also askubuntu.com/q/138623)
askubuntu.com/q/50540 ::: What is Ubuntu's Definition of a "Registered Application"?
askubuntu.com/q/53762 ::: How to use lm-sensors?
askubuntu.com/q/53762 ::: how-to-use-to-use-lm-sensors
stackoverflow.com/q/4594319 ::: bash - shell replace cr\lf by comma
stackoverflow.com/q/4594319 ::: shell replace cr\lf by comma
wiki.ubuntu.com/ClipboardPersistence ::: ClipboardPersistence
wiki.ubuntu.com/ClipboardPersistence ::: ClipboardPersistence - Ubuntu Wiki
www.youtube.com/watch?v=1olY5Qzmbk8 ::: Create new mime types in Ubuntu
www.youtube.com/watch?v=2hu9JrdSXB8 ::: Change mouse cursor
www.youtube.com/watch?v=Yxfa2fXJ1Wc ::: Mouse cursor size

, поскольку список короток, я вижу (после сортировки), что существует три набора дубликатов.

Затем например, я могу принять решение сохранить:

askubuntu.com/q/53762 ::: How to use lm-sensors?

, а не

askubuntu.com/q/53762 ::: how-to-use-to-use-lm-sensors

, Но для более длинного списка это будет трудно. На основе двух ответов одно предложение uniq и другое предложение cut, я нахожу, что эта команда дает мне вывод, который я хотел бы:

$ cut -d " " -f1 file.txt | uniq -d
askubuntu.com/q/53762
stackoverflow.com/q/4594319
wiki.ubuntu.com/ClipboardPersistence
$
0
ответ дан 16.05.2020, 09:52
  • 1
    Я обновил свой ответ с другим вариантом cut. Если Вы делаете работу дедупликации, то номера строки могут быть очень полезными. Для печати всех дубликатов используйте -D опция вместо -d. – Ankit Nigam 16.05.2020, 09:53
  • 2
    Я думаю, что Вы лучше используете: for dup in $(cut -d " " -f1 file.txt | uniq -d); do grep -n $dup file.txt; done как в моем ответе. Это даст Вам лучший предварительный просмотр о том, что Вам интересно. – James Webster 16.05.2020, 09:53

Если я считал это правильно, все, в чем Вы нуждаетесь, что-то как [1 118]

awk '{print $1}' file | sort | uniq -c | 
    while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done

, Который распечатает количество строки, которая содержит простофилю и саму строку. Например, использование этого файла:

foo bar baz
http://unix.stackexchange.com/questions/49569/  unique-lines-based-on-the-first-field
bar foo baz
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field   sort, CLI
baz foo bar
http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field

Это произведет этот вывод:

2:http://unix.stackexchange.com/questions/49569/  unique-lines-based-on-the-first-field
4:http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field   sort, CLI
6:http://unix.stackexchange.com/questions/49569/  Unique lines based on the first field

Для печати только количества строки Вы могли сделать

awk '{print $1}' file | sort | uniq -c | 
 while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 1

И распечатать только строку:

awk '{print $1}' file | sort | uniq -c | 
while read num dupe; do [[ $num > 1 ]] && grep -n -- "$dupe" file; done | cut -d: -f 2-
<час>

Объяснение:

awk сценарий просто печатает разделенное поле 1-го пространства файла. Используйте $N для печати поля Nth. sort виды это и uniq -c количества случаи каждой строки.

Это тогда передается while цикл, который сохраняет количество случаев как [1 110] и строка как [1 111] и если $num будет больше, чем один (таким образом, это дублировано, по крайней мере, однажды), то это будет искать файл ту строку, с помощью [1 113] для печати номера строки. Эти -- говорит grep, что то, что следует, не является параметром командной строки, полезным для того, когда $dupe может запуститься с [1 117].

2
ответ дан 16.05.2020, 09:53

Несомненно самый подробный в списке, могло, вероятно, быть короче:

#!/usr/bin/python3
import collections
file = "file.txt"

def find_duplicates(file):
    with open(file, "r") as sourcefile:
        data = sourcefile.readlines()
    splitlines = [
        (index, data[index].split("  ")) for index in range(0, len(data))
        ]
    lineheaders = [item[1][0] for item in splitlines]
    dups = [x for x, y in collections.Counter(lineheaders).items() if y > 1]
    dupsdata = []
    for item in dups:
        occurrences = [
            splitlines_item[0] for splitlines_item in splitlines\
                       if splitlines_item[1][0] == item
            ]
        corresponding_lines = [
            "["+str(index)+"] "+data[index] for index in occurrences
            ]
        dupsdata.append((occurrences, corresponding_lines))

    # printing output   
    print("found duplicates:\n"+"-"*17)
    for index in range(0, len(dups)):
        print(dups[index], dupsdata[index][0])
        lines = [item for item in dupsdata[index][1]]
        for line in lines:
            print(line, end = "")


find_duplicates(file)

дает на текстовом файле как:

monkey  banana
dog  bone
monkey  banana peanut
cat  mice
dog  cowmeat

вывод как:

found duplicates:
-----------------
dog [1, 4]
[1] dog  bone
[4] dog  cowmeat
monkey [0, 2]
[0] monkey  banana
[2] monkey  banana peanut

, Как только Вы выбрали строки для удаления:

removelist = [2,1]

def remove_duplicates(file, removelist):
    removelist = sorted(removelist, reverse=True)
    with open(file, "r") as sourcefile:
        data = sourcefile.readlines()
    for index in removelist:
        data.pop(index)
    with open(file, "wt") as sourcefile:
        for line in data:
            sourcefile.write(line)

remove_duplicates(file, removelist)
1
ответ дан 16.05.2020, 09:53

Ее то, как я решил его:

file_with_duplicates:

1,a,c
2,a,d
3,a,e <--duplicate
4,a,t
5,b,k <--duplicate
6,b,l
7,b,s
8,b,j
1,b,l
3,a,d <--duplicate
5,b,l <--duplicate

Файл, отсортированный и дедуплицированный столбцами 1 и 2:

sort -t',' -k1,1 -k2,2 -u file_with_duplicates

Файл, отсортированный только по столбцам 1 и 2:

sort -t',' -k1,1 -k2,2 file_with_duplicates

Шоу различие только:

diff <(sort -t',' -k1,1 -k2,2 -u file_with_duplicates) <(sort -t',' -k1,1 -k2,2 file_with_duplicates)

 3a4
   3,a,d
 6a8
   5,b,l
0
ответ дан 16.05.2020, 09:54

Теги

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