сделать сортировку / сравнение python так же, как сортировку GNU - PullRequest
3 голосов
/ 02 октября 2019

После первых тестов кажется, что Python использует тот же порядок сортировки, что и для сортировки Linux (gnu sort) с порядком сортировки C (если языковой стандарт установлен в "C").

Однако яхотелось бы иметь возможность писать код Python, который сортирует и сравнивает так же, как сортировка gnu, в зависимости от локали.

Небольшой пример кода, иллюстрирующий проблему:

import os 
import subprocess

words = [
    "Abd",
    "éfg",
    "aBd",
    "aBd",
    "zzz",
    "ZZZ",
    "efg",
    "abd",
    "fff",
    ]

with open("tosort", "w") as fout:
    for word in words:
        fout.write(word + "\n")

os.environ["LC_ALL"] = "en_US.UTF-8" 
proc = subprocess.Popen(["sort", "tosort"], stdout=subprocess.PIPE)
sort_en_utf = proc.stdout.read().decode('utf-8').split()

os.environ["LC_ALL"] = "C" 
proc = subprocess.Popen(["sort", "tosort"], stdout=subprocess.PIPE) 
sort_c = proc.stdout.read().decode('utf-8').split()

os.environ["LC_ALL"] = "en_US.UTF-8"
sort_py = sorted(words)

for row in zip(sort_en_utf, sort_c, sort_py):
    print(" ".join(row))

ЕслиПриведенный выше код запускается, я получаю следующий вывод:

abd Abd Abd
aBd ZZZ ZZZ
aBd aBd aBd
Abd aBd aBd
efg abd abd
éfg efg efg
fff fff fff
zzz zzz zzz
ZZZ éfg éfg

столбец 1 - это порядок сортировки / сравнения, который я хотел бы иметь в своем коде Python, если локаль - "en_US.UTF-8", столбец 2и 3 показывают, что python сортирует так же, как linux ', если локаль установлена ​​на "C".

Так что я также хотел бы узнать, есть ли способ получить:

"éfg" < "fff" выход True. Я не настаиваю на операторе сравнения, я также могу вызвать функцию. но результат упорядочения должен учитывать текущую локаль.

1 Ответ

1 голос
/ 02 октября 2019

Хммм, как-то я упустил это из виду:

Документ о сортировке python https://docs.python.org/3.5/howto/sorting.html упоминает в последнем разделе "Шансы и конец" функцию locale.strxfrm () (см. * 1006). *) в качестве ключевой функции для сортировки, а locale.strcoll () - в качестве функции сравнения.

Таким образом, следующий измененный код является почти нормальным, за исключением того, что функция сравнения не возвращает напрямую true / false, но это нормально вмой контекст

import subprocess

words = [
    "Abd",
    "éfg",
    "aBd",
    "aBd",
    "zzz",
    "ZZZ",
    "efg",
    "abd",
    "fff",
    "sra",
    "ssa",
    "ssb",
    "stb",
    "ßaa",
    ]

val1 = "ßaa"
val2 = "ssb"

with open("tosort", "w") as fout:
    for word in words:
        fout.write(word + "\n")

os.environ["LC_ALL"] = "en_US.UTF-8"
proc = subprocess.Popen(["sort", "tosort"], stdout=subprocess.PIPE)
sort_en_utf = proc.stdout.read().decode('utf-8').split()

os.environ["LC_ALL"] = "C"
proc = subprocess.Popen(["sort", "tosort"], stdout=subprocess.PIPE)
sort_c = proc.stdout.read().decode('utf-8').split()

locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
sort_py1 = sorted(words, key=lambda v: locale.strxfrm(v))
print("%r < %r = %s , but locale.strcoll(%r, %r) = %s for %s"
      % (val1, val2, val1 < val2, val1, val2,
         locale.strcoll(val1, val2), locale.getlocale())
      )

locale.setlocale(locale.LC_ALL, "C")
sort_py2 = sorted(words, key=lambda v: locale.strxfrm(v))
print("%r < %r = %s , but locale.strcoll(%r, %r) = %s for %s"
      % (val1, val2, val1 < val2, val1, val2,
         locale.strcoll(val1, val2), locale.getlocale())
      )

for row in zip(sort_en_utf, sort_py1, sort_c, sort_py2):
    print(" ".join(row))

Вывод будет

'ßaa' < 'ssb' = False , but locale.strcoll('ßaa', 'ssb') = -1 for ('en_US', 'UTF-8')
'ßaa' < 'ssb' = False , but locale.strcoll('ßaa', 'ssb') = 1 for (None, None)
abd abd Abd Abd
aBd aBd ZZZ ZZZ
aBd aBd aBd aBd
Abd Abd aBd aBd
efg efg abd abd
éfg éfg efg efg
fff fff fff fff
sra sra sra sra
ssa ssa ssa ssa
ßaa ßaa ssb ssb
ssb ssb stb stb
stb stb zzz zzz
zzz zzz ßaa ßaa
ZZZ ZZZ éfg éfg
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...