|
186 | 186 | "execution_count": null, |
187 | 187 | "id": "8079ef9d", |
188 | 188 | "metadata": {}, |
189 | | - "outputs": [], |
| 189 | + "outputs": [ |
| 190 | + { |
| 191 | + "data": { |
| 192 | + "text/plain": [ |
| 193 | + "'a-b\\nb a'" |
| 194 | + ] |
| 195 | + }, |
| 196 | + "execution_count": null, |
| 197 | + "metadata": {}, |
| 198 | + "output_type": "execute_result" |
| 199 | + } |
| 200 | + ], |
190 | 201 | "source": [ |
191 | 202 | "res = str_replace('keep q\\nfix q\\nkeep q', 'q', 'y', re_filter='fix')\n", |
192 | 203 | "test_eq(res, 'keep q\\nfix y\\nkeep q')\n", |
|
371 | 382 | "metadata": {}, |
372 | 383 | "source": [ |
373 | 384 | "#| export\n", |
374 | | - "`line_hash`, `lnhash` and `lnhash_at` create [exhash](https://answerdotai.github.io/exhash) addresses without depending on the exhash package. Addresses use `lineno|hash|`. The hash is the low 16 bits of CRC32, formatted as four hexadecimal characters." |
| 385 | + "`line_hash`, `lnhash` and `lnhash_at` create [exhash](https://answerdotai.github.io/exhash) addresses without depending on the exhash package. Addresses use `lineno|hash|`. The hash is the low 12 bits of CRC32, encoded as two Base64url characters (`A–Z`, `a–z`, `0–9`, `-`, `_`), high six bits first." |
375 | 386 | ] |
376 | 387 | }, |
377 | 388 | { |
|
385 | 396 | "def line_hash(\n", |
386 | 397 | " line:str # Text to hash; when hashing a single line, omit its trailing newline\n", |
387 | 398 | ")->str:\n", |
388 | | - " \"4-char hex hash of `line`\"\n", |
389 | | - " return f'{zlib.crc32(line.encode()) & 0xffff:04x}'\n", |
| 399 | + " \"2-char Base64url hash of `line`\"\n", |
| 400 | + " alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'\n", |
| 401 | + " h = zlib.crc32(line.encode())\n", |
| 402 | + " return alphabet[(h>>6)&63] + alphabet[h&63]\n", |
390 | 403 | "\n", |
391 | 404 | "def lnhash(\n", |
392 | 405 | " lineno:int, # 1-based line number\n", |
|
413 | 426 | { |
414 | 427 | "data": { |
415 | 428 | "text/plain": [ |
416 | | - "'2|54f0|'" |
| 429 | + "'2|Tw|'" |
417 | 430 | ] |
418 | 431 | }, |
419 | 432 | "execution_count": null, |
|
422 | 435 | } |
423 | 436 | ], |
424 | 437 | "source": [ |
425 | | - "test_eq(line_hash('def foo(): pass'), '54f0') # same value the exhash Rust impl produces\n", |
| 438 | + "test_eq(line_hash('def foo(): pass'), 'Tw') # same value the exhash Rust impl produces\n", |
426 | 439 | "s = 'a\\ndef foo(): pass\\nb'\n", |
427 | | - "test_eq(lnhash_at(s, 2), '2|54f0|')\n", |
428 | | - "test_eq(lnhash_at(s.splitlines(), 2), '2|54f0|')\n", |
| 440 | + "test_eq(lnhash_at(s, 2), '2|Tw|')\n", |
| 441 | + "test_eq(lnhash_at(s.splitlines(), 2), '2|Tw|')\n", |
429 | 442 | "test_eq(lnhash_at(s, 2), lnhash(2, 'def foo(): pass'))\n", |
430 | 443 | "lnhash_at(s, 2)" |
431 | 444 | ] |
|
493 | 506 | { |
494 | 507 | "data": { |
495 | 508 | "text/plain": [ |
496 | | - "'/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/tmpaax7zfjh/test.txt'" |
| 509 | + "'/var/folders/mv/nt5dfl8j0xbg7zkfw_sk_d8m0000gn/T/tmpxaep7ttt/test.txt'" |
497 | 510 | ] |
498 | 511 | }, |
499 | 512 | "execution_count": null, |
|
542 | 555 | { |
543 | 556 | "data": { |
544 | 557 | "text/plain": [ |
545 | | - "2|0463|beta\n", |
546 | | - "3|d071|gamma" |
| 558 | + "2|Rj|beta\n", |
| 559 | + "3|Bx|gamma" |
547 | 560 | ] |
548 | 561 | }, |
549 | 562 | "execution_count": null, |
|
0 commit comments