Utilitaire de vidage hexadécimal réversible (alias «xxd»)

12

xxdest un utilitaire, fourni avec vim, qui a été utilisé pour coder les réponses aux problèmes de code de golf sur ce site. Il convertit un fichier binaire en un vidage hexadécimal et vice-versa.

Implémentez les commandes xxdet xxd -rdans le ou les langages de programmation de votre choix. La notation est basée sur les longueurs de caractères / octets de a) vos programmes et b) tout argument de ligne de commande nécessaire pour commuter un programme combiné entre les modes (ils n'ont pas besoin de l'être -r). Comme au golf, des scores plus bas sont meilleurs.

  • Pour deux programmes distincts: code avant + code inverse
  • Pour un programme combiné: code combiné + somme ( arguments avancés ) + somme ( arguments inverses ) - 2

Spécification du xxdsous-ensemble choisi

La commande de transfert ( par exemple xxd ) accepte 0 ≤ n ≤ 2 16 octets à partir de l'entrée standard et génère des lignes plafond ( n / 16) de sortie standard dans le format suivant (tous les chiffres hexadécimaux en minuscules):

  • Décalage du premier octet codé (chaîne de format "%07x:"); fini dans"0"
  • Au plus 16 octets codés en hexadécimal, regroupés en paires (chaîne de format " %02x"pour les octets pairs, "%02x"pour les octets impairs) et remplis à droite avec des espaces de 42 caractères
  • Les octets codés interprétés comme des caractères ASCII, les valeurs ne se situant pas entre 0x20 et 0x7e ( '\40'et '\176') inclusivement devenant"."
  • Une nouvelle ligne ( "\n"; "\r\n"autorisée lorsque la sortie standard est en mode binaire)

Implémentation C minimale non golfée:

#include <stdio.h>
int main() {
    unsigned char L[16];
    int t = 0, n, i, s;

    for (; (n = fread(L, 1, 16, stdin)); t += n) {
        printf("%07x:", t);
        s = 42;
        for (i = 0; i < n; i++)
            s -= printf(i & 1 ? "%02x" : " %02x", L[i]);
        printf("%*s", s, "");
        for (i = 0; i < n; i++)
            putchar(L[i] > '\37' && L[i] < '\177' ? L[i] : '.');
        printf("\n");
    }

    return 0;
}

La commande inverse ( par exemple xxd -r ) accepte toute sortie non modifiée de la commande directe (en fonction d'une entrée valide pour cette commande) et produit cette entrée d'origine.

Exemple d'utilisation

$ xxd < /dev/null | wc -c
0
$ php -r 'echo join(range("\0",~"\0"));' | xxd
0000000: 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f  ................
0000010: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f  ................
0000020: 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f   !"#$%&'()*+,-./
0000030: 3031 3233 3435 3637 3839 3a3b 3c3d 3e3f  0123456789:;<=>?
0000040: 4041 4243 4445 4647 4849 4a4b 4c4d 4e4f  @ABCDEFGHIJKLMNO
0000050: 5051 5253 5455 5657 5859 5a5b 5c5d 5e5f  PQRSTUVWXYZ[\]^_
0000060: 6061 6263 6465 6667 6869 6a6b 6c6d 6e6f  `abcdefghijklmno
0000070: 7071 7273 7475 7677 7879 7a7b 7c7d 7e7f  pqrstuvwxyz{|}~.
0000080: 8081 8283 8485 8687 8889 8a8b 8c8d 8e8f  ................
0000090: 9091 9293 9495 9697 9899 9a9b 9c9d 9e9f  ................
00000a0: a0a1 a2a3 a4a5 a6a7 a8a9 aaab acad aeaf  ................
00000b0: b0b1 b2b3 b4b5 b6b7 b8b9 babb bcbd bebf  ................
00000c0: c0c1 c2c3 c4c5 c6c7 c8c9 cacb cccd cecf  ................
00000d0: d0d1 d2d3 d4d5 d6d7 d8d9 dadb dcdd dedf  ................
00000e0: e0e1 e2e3 e4e5 e6e7 e8e9 eaeb eced eeef  ................
00000f0: f0f1 f2f3 f4f5 f6f7 f8f9 fafb fcfd feff  ................
$ xxd <<< 'The quick brown fox jumps over the lazy dog.'
0000000: 5468 6520 7175 6963 6b20 6272 6f77 6e20  The quick brown 
0000010: 666f 7820 6a75 6d70 7320 6f76 6572 2074  fox jumps over t
0000020: 6865 206c 617a 7920 646f 672e 0a         he lazy dog..
$ xxd <<< 'The quick brown fox jumps over the lazy dog.' | xxd -r
The quick brown fox jumps over the lazy dog.
Veuillez vous lever
la source
Le mode inverse doit-il ignorer les caractères ASCII incorrects? (FWIW fait le xxd réel, ce qui est assez utile).
Peter Taylor
@PeterTaylor: Le mode inverse ne doit fonctionner correctement qu'avec des vidages hexadécimaux non modifiés (à partir de 0000000, des chiffres hexadécimaux en minuscules, 16 octets sur toutes les lignes mais la dernière, aucun espace, etc. ), et la validation des entrées n'est pas requise. Cela dit, il est probablement logique d'ignorer la colonne "ASCII" à 16 caractères à droite, car elle ne peut pas être utilisée pour distinguer "." et les caractères non imprimables.
PleaseStand

Réponses:

3

Perl, 122 + 54 = 176 122 + 45 = 167

Le script avancé:

$/=$,;for(<>=~/.{1,16}/gs){$h="";$h.=sprintf"%*s%02x",++$m%2,"",ord for/./gs;
s/[^ -~]/./g;printf"%06x0:%-42s",$n++,$h;say}

Et le script inverse:

/:(.+?)  /,print map{chr hex}$1=~/\w\w/gfor<>

(Celui-ci est intéressant; il y a toutes sortes de bugs obscurs qui peuvent apparaître dans le script inverse en fonction de l'entrée, si vous ne faites pas attention.)

boite à pain
la source
Depuis $1est connu que pour contenir les chiffres hexagonaux et des espaces, pouvez - vous pas utiliser au /\w\w/lieu de /[0-9a-f]{2}/?
Neil
$1contient beaucoup de choses en plus des chiffres hexadécimaux et des espaces.
boîte à pain le
Dans l'exemple, je ne vois que des chiffres hexadécimaux et des espaces entre le : et le ``.
Neil
(Quelqu'un sait comment générer deux espaces monospaces dans le commentaire de réduction?)
Neil
@Neil Peu importe, j'ai mal lu mon propre code. Je ne me souviens pas maintenant pourquoi je n'ai pas simplement utilisé /\w\w/. Cela semble si évident que je sens que je dois avoir une raison, mais je ne peux pas en voir une. Ma meilleure supposition est que c'était un résidu d'une version qui essayait d'éviter d'exiger l'expression régulière initiale.
boîte à pain le