การถอดรหัสการเข้ารหัส URL (การเข้ารหัสเป็นเปอร์เซ็นต์)


100

ฉันต้องการถอดรหัสการเข้ารหัส URL มีเครื่องมือในตัวสำหรับการทำเช่นนี้หรือใครสามารถให้sedรหัสที่จะทำเช่นนี้ได้หรือไม่

ฉันค้นหาบิตผ่านunix.stackexchange.comและบนอินเทอร์เน็ต แต่ฉันไม่พบเครื่องมือบรรทัดคำสั่งใด ๆ สำหรับการถอดรหัสการเข้ารหัส URL

สิ่งที่ฉันต้องการทำคือแก้ไขtxtไฟล์เพื่อที่:

  • %21 กลายเป็น !
  • %23 กลายเป็น #
  • %24 กลายเป็น $
  • %26 กลายเป็น &
  • %27 กลายเป็น '
  • %28 กลายเป็น (
  • %29 กลายเป็น )

และอื่น ๆ


คำตอบ:


107

พบ Python หนึ่ง liners ที่ทำสิ่งที่คุณต้องการ:

$ alias urldecode='python -c "import sys, urllib as ul; \
    print ul.unquote_plus(sys.argv[1])"'

$ alias urlencode='python -c "import sys, urllib as ul; \
    print ul.quote_plus(sys.argv[1])"'

ตัวอย่าง

$ urldecode 'q+werty%3D%2F%3B'
q werty=/;

$ urlencode 'q werty=/;'
q+werty%3D%2F%3B

อ้างอิง


ฉันรู้เรื่องนี้ช้ามาก แต่มีวิธีใดบ้างที่ฉันสามารถทำได้ด้วยการแก้ไขในสถานที่?
DisplayName

@DisplayName - ฟังดูเหมือนคำถามใหม่สำหรับฉัน ฉันถามแล้วอ้างอิงนี่
slm

15
การสตรีม:cat your_lovely_file.csv| python -c "import sys, urllib as ul; [sys.stdout.write(ul.quote_plus(l)) for l in sys.stdin]"
kirill_igum

5
โปรดทราบว่านี่คือ Python 2 บนระบบที่pythonเป็น 3 โดยค่าเริ่มต้นนี้จะส่งผลให้เกิดข้อผิดพลาด การเปลี่ยนpythonไปpython2ช่วย
Ivan Kolmychek

4
สำหรับpython3คุณสามารถใช้แทนimport urllib.parse as ul import urllib as ul
ibotty

61

sed

ลองใช้บรรทัดคำสั่งต่อไปนี้:

$ sed 's@+@ @g;s@%@\\x@g' file | xargs -0 printf "%b"

หรือทางเลือกต่อไปนี้โดยใช้echo -e:

$ sed -e's/%\([0-9A-F][0-9A-F]\)/\\\\\x\1/g' file | xargs echo -e

หมายเหตุ: ไวยากรณ์ข้างต้นอาจไม่แปลง+เป็นช่องว่างและสามารถขึ้นบรรทัดใหม่ได้ทั้งหมด


คุณอาจกำหนดเป็นนามแฝงและเพิ่มลงในไฟล์shell rcของคุณ:

$ alias urldecode='sed "s@+@ @g;s@%@\\\\x@g" | xargs -0 printf "%b"'

จากนั้นทุกครั้งที่คุณต้องการเพียงแค่ไปกับ:

$ echo "http%3A%2F%2Fwww" | urldecode
http://www

ทุบตี

เมื่อสคริปต์คุณสามารถใช้ไวยากรณ์ต่อไปนี้:

input="http%3A%2F%2Fwww"
decoded=$(printf '%b' "${input//%/\\x}")

แต่เหนือไวยากรณ์จะไม่จัดการ pluses ( +) sedอย่างถูกต้องเพื่อให้คุณได้เพื่อแทนที่พวกเขามีช่องว่างทาง

คุณยังสามารถใช้ฟังก์ชั่นurlencode()และurldecode()ฟังก์ชั่นต่อไปนี้:

urlencode() {
    # urlencode <string>
    local length="${#1}"
    for (( i = 0; i < length; i++ )); do
        local c="${1:i:1}"
        case $c in
            [a-zA-Z0-9.~_-]) printf "$c" ;;
            *) printf '%%%02X' "'$c" ;;
        esac
    done
}

urldecode() {
    # urldecode <string>

    local url_encoded="${1//+/ }"
    printf '%b' "${url_encoded//%/\\x}"
}

โปรดทราบว่าข้างต้นurldecode()ถือว่าข้อมูลไม่มีเครื่องหมายแบ็กสแลช

นี่คือรุ่นของ Joel ที่คล้ายกันที่พบได้ที่: https://github.com/sixarm/urldecode.sh


bash + xxd

ฟังก์ชั่นทุบตีด้วยxxdเครื่องมือ:

urlencode() {
  local length="${#1}"
  for (( i = 0; i < length; i++ )); do
    local c="${1:i:1}"
    case $c in
      [a-zA-Z0-9.~_-]) printf "$c" ;;
    *) printf "$c" | xxd -p -c1 | while read x;do printf "%%%s" "$x";done
  esac
done
}

พบในไฟล์เค้า cdown ของยังที่StackOverflow


PHP

ใช้ PHP คุณสามารถลองคำสั่งต่อไปนี้:

$ echo oil+and+gas | php -r 'echo urldecode(fgets(STDIN));' // Or: php://stdin
oil and gas

หรือเพียงแค่:

php -r 'echo urldecode("oil+and+gas");'

ใช้-Rสำหรับอินพุตหลายบรรทัด


Perl

ใน Perl URI::Escapeคุณสามารถใช้

decoded_url=$(perl -MURI::Escape -e 'print uri_unescape($ARGV[0])' "$encoded_url")

หรือเพื่อประมวลผลไฟล์:

perl -i -MURI::Escape -e 'print uri_unescape($ARGV[0])' file

awk

ลองอานนท์แก้ปัญหา:

awk -niord '{printf RT?$0chr("0x"substr(RT,2)):$0}' RS=%..

หมายเหตุ: พารามิเตอร์-nเป็นเฉพาะกับ awkGNU

ดู: การใช้ printf awk เพื่อ urldecode ข้อความ

การถอดรหัสชื่อไฟล์

หากคุณต้องการลบการเข้ารหัส URL ออกจากชื่อไฟล์ให้ใช้deurlnameเครื่องมือจากrenameutils(เช่นdeurlname *.*)

ดูสิ่งนี้ด้วย:


ที่เกี่ยวข้อง:


1
awk: เนื่องจากจะใช้ประโยชน์จากฟังก์ชั่นห้องสมุดchr()จึงมีความเป็นไปได้สูงที่จะใช้กับ GNU awk ( gawk) เท่านั้น อย่างไรก็ตามในกรณีนี้จะมี POSIX แทบจะไม่เทียบเท่าawkเพราะ-nตัวเลือก (อนุญาตให้อาร์กิวเมนต์ที่ไม่ใช่ทศนิยม) เป็น GNU awkชนิดพิเศษ
ไวยากรณ์

sedรหัสแรกของคุณให้ฉันxargs: argument line too longไฟล์ที่มี≥2164บรรทัด
Sparhawk

2
การแก้ปัญหาของคุณที่เกี่ยวข้องกับการprintfไม่คำนึงถึงว่า URL %25ที่อาจมีสัญญาณหนีเปอร์เซ็นต์เช่น คุณผ่านเหล่านี้เพื่อ printf โดยไม่ต้องหลบหนีพวกเขาสำหรับ printf %%อีกด้วยเครื่องหมายเปอร์เซ็นต์เช่น
josch

1
เวอร์ชันทุบตีต้องการlocal LC_ALL=Cที่ด้านบนมิฉะนั้นอักขระที่มีความกว้างทั้งหมด (เช่นญี่ปุ่นจีน ฯลฯ ) จะไม่ถูกแบ่งเป็นไบต์อย่างถูกต้อง
Phernost


18

มีฟังก์ชั่นในตัวสำหรับที่อยู่ในไลบรารี Python มาตรฐาน ในหลาม 2 urllib.unquoteก็

decoded_url=$(python2 -c 'import sys, urllib; print urllib.unquote(sys.argv[1])' "$encoded_url")

หรือเพื่อประมวลผลไฟล์:

python2 -c 'import sys, urllib; print urllib.unquote(sys.stdin.read())' <file >file.new &&
mv -f file.new file

ในหลาม 3 urllib.parse.unquoteก็

decoded_url=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.unquote(sys.argv[1]))' "$encoded_url")

หรือเพื่อประมวลผลไฟล์:

python3 -c 'import sys, urllib; print(urllib.parse.unquote(sys.stdin.read()))' <file >file.new &&
mv -f file.new file

ใน Perl URI::Escapeคุณสามารถใช้

decoded_url=$(perl -MURI::Escape -e 'print uri_unescape($ARGV[0])' "$encoded_url")

หรือเพื่อประมวลผลไฟล์:

perl -i -MURI::Escape -e 'print uri_unescape($ARGV[0])' file

หากคุณต้องการติดตั้งเครื่องมือพกพา POSIX มันน่าอึดอัดใจเพราะผู้สมัครที่ร้ายแรงเพียงคนเดียวคือ awk ซึ่งไม่ได้แยกตัวเลขฐานสิบหก ดูที่การใช้ awk printf เพื่อ urldecode textสำหรับตัวอย่างที่มีการใช้งาน awk ทั่วไปรวมถึง BusyBox


10

หากคุณต้องการใช้sedคำสั่งแบบง่าย ๆ ให้ใช้คำสั่งต่อไปนี้:

sed -e 's/%21/!/g' -e 's/%23/#/g' -e 's/%24/$/g' -e 's/%26/\&/g' -e "s/%27/'/g" -e 's/%28/(/g' -e 's/%29/)/g'

แต่การสร้างสคริปต์จะสะดวกกว่า (พูดsedscript):

s/%21/!/g
s/%23/#/g
s/%24/$/g
s/%26/\&/g
s/%27/'/g
s/%28/(/g
s/%29/)/g

จากนั้นเรียกใช้sed -f sedscript < old > newซึ่งจะส่งออกตามที่คุณต้องการ


เพื่อความสะดวกคำสั่งurlencodeนั้นยังมีให้ในgridsite-clientsแพ็คเกจโดยตรงสามารถติดตั้งได้ (โดยsudo apt-get install gridsite-clientsในระบบ Ubuntu / Debian)

ชื่อ

    urlencode - แปลงสตริงเป็นหรือจากรูปแบบการเข้ารหัส URL
สรุป

    urlencode [-m|-d] string [string ...]

รายละเอียด

    urlencode เข้ารหัสสตริงตาม RFC 1738

    นั่นคือตัวอักษรA- Z a- z 0- 9 . _และ-ถูกส่งผ่านโดยไม่ได้แก้ไข แต่ตัวละครอื่น ๆ ทั้งหมดจะแสดงเป็น% HH โดยที่ HH คือการเป็นตัวแทน ASCII เลขฐานสิบหกสองตัวบน ตัวอย่างเช่น URL http://www.gridpp.ac.uk/จะกลายเป็นhttp%3A%2F%2Fwww.gridpp.ac.uk%2F

    urlencodeแปลงอักขระแต่ละตัวในสตริงทั้งหมดที่กำหนดในบรรทัดคำสั่ง หากมีการกำหนดสตริงจำนวนมากสตริงเหล่านี้จะถูกต่อกันด้วยการแยกช่องว่างก่อนการแปลง

ตัวเลือก
    -m
      แทนที่จะทำการแปลงแบบเต็มอย่าเลือก GridSite "การเข้ารหัส URL ที่ไม่รุนแรง" ซึ่ง AZ az 0-9 = - _ @ และ / จะถูกส่งผ่านโดยไม่แก้ไข สิ่งนี้ส่งผลให้สายอักขระที่มนุษย์สามารถอ่านได้เพิ่มขึ้นเล็กน้อย แต่แอปพลิเคชันจะต้องเตรียมที่จะสร้างหรือจำลองไดเรกทอรีที่ส่อให้เห็น
    -d
      ทำการถอดรหัส URL แทนที่จะเข้ารหัสตามสตริง RFC 1738%% HH และ% hh จะถูกแปลงและอักขระอื่น ๆ จะถูกส่งผ่านไปยังที่ไม่ได้แก้ไขโดยมีข้อยกเว้นที่+ถูกแปลงเป็นช่องว่าง

ตัวอย่างของการถอดรหัส URL:

$ urlencode -d "http%3a%2f%2funix.stackexchange.com%2f"
http://unix.stackexchange.com/

$ urlencode -d "Example: %21, %22, . . . , %29 etc"
Example: !, ", . . . , ) etc

สำหรับการสอนเกี่ยวกับการsed เยี่ยมชม
Pandya

4
นี่เป็นวิธีการแก้ปัญหาที่ไม่ดีเพราะมันต้องใช้ฮาร์ดโค้ดทุกตัวละคร ปัญหานี้เกิดขึ้นจากรหัสของคุณที่ไม่มี%20ลำดับการหลีกเลี่ยงที่ใช้บ่อย
โอเวอร์

@Overv ฉันเพิ่งแก้ไข
Pandya

นอกจากนี้คุณอาจต้องการตรวจสอบอีกครั้งว่ามีอะไรs/%26/&/gบ้าง (ฉันแก้ไขมัน)
G-Man

9

Perl หนึ่งซับ:

$ perl -pe 's/\%(\w\w)/chr hex $1/ge'

ตัวอย่าง:

$ echo '%21%22' |  perl -pe 's/\%(\w\w)/chr hex $1/ge'
!"

1
คำตอบนี้น่าสนใจเมื่อคุณไม่ต้องการจัดการกับการติดตั้งโมดูล perl
Sridhar Sarnobat

1
หนึ่งเดียวที่ทำงานได้อย่างหรูหราสำหรับฉันบน MacOS
Qix


7

ฉันไม่สามารถแสดงความคิดเห็นกับคำตอบที่ดีที่สุดในหัวข้อนี้ดังนั้นนี่คือของฉัน

ส่วนตัวผมใช้นามแฝงเหล่านี้เพื่อการเข้ารหัสและถอดรหัส URL:

alias urlencode='python -c "import urllib, sys; print urllib.quote(  sys.argv[1] if len(sys.argv) > 1 else sys.stdin.read()[0:-1])"'

alias urldecode='python -c "import urllib, sys; print urllib.unquote(sys.argv[1] if len(sys.argv) > 1 else sys.stdin.read()[0:-1])"'

ทั้งสองคำสั่งอนุญาตให้คุณแปลงข้อมูลส่งผ่านเป็นอาร์กิวเมนต์บรรทัดคำสั่งหรืออ่านจากอินพุตมาตรฐานเนื่องจากทั้งสอง liners ตรวจสอบว่ามีอาร์กิวเมนต์บรรทัดคำสั่ง (แม้แต่ที่ว่างเปล่า) และประมวลผลพวกเขาหรือเพียงแค่อ่านอินพุตมาตรฐานมิฉะนั้น


อัพเดท 2017-05-23 (การเข้ารหัสสแลช)

เพื่อตอบสนองต่อความคิดเห็นของ @ Bevor

หากคุณต้องการเข้ารหัสสแลชให้เพิ่มอาร์กิวเมนต์ที่สองที่ว่างในฟังก์ชันอัญประกาศจากนั้นสแลชจะถูกเข้ารหัส

ดังนั้นในที่สุดurlencode นามแฝงในbashจะมีลักษณะดังนี้:

alias urlencode='python -c "import urllib, sys; print urllib.quote(sys.argv[1] if len(sys.argv) > 1 else sys.stdin.read()[0:-1], \"\")"'

ตัวอย่าง

$ urlencode "Проба пера/Pen test"
%D0%9F%D1%80%D0%BE%D0%B1%D0%B0%20%D0%BF%D0%B5%D1%80%D0%B0%2FPen%20test

$ echo "Проба пера/Pen test" | urlencode
%D0%9F%D1%80%D0%BE%D0%B1%D0%B0%20%D0%BF%D0%B5%D1%80%D0%B0%2FPen%20test

$ urldecode %D0%9F%D1%80%D0%BE%D0%B1%D0%B0%20%D0%BF%D0%B5%D1%80%D0%B0%2FPen%20test
Проба пера/Pen test

$ echo "%D0%9F%D1%80%D0%BE%D0%B1%D0%B0%20%D0%BF%D0%B5%D1%80%D0%B0%2FPen%20test" | urldecode
Проба пера/Pen test

$ urlencode "Проба пера/Pen test" | urldecode
Проба пера/Pen test

$ echo "Проба пера/Pen test" | urlencode | urldecode
Проба пера/Pen test

1
ห้ามเข้ารหัสสแลช
Bevor

@Bevor: ตัวอย่าง?
DIG mbl

เพิ่มเครื่องหมายสแลชไปที่ urlencode "Пробапера" -> ผล: สแลชไม่ได้เข้ารหัส
Bevor

1
@Bevor: คุณพูดถูก ขอบคุณสำหรับความคิดเห็นของคุณ. ฉันจะเปลี่ยนคำตอบเพื่อแสดงความคิดเห็นของคุณ
DIG mbl

4

และอีกวิธี Perl:

#!/usr/bin/env perl
use URI::Encode;
my $uri     = URI::Encode->new( { encode_reserved => 0 } );
while (<>) {

    print $uri->decode($_)
}

คุณจะต้องติดตั้งURI::Encodeโมดูล บน Debian ของฉันฉันสามารถวิ่งได้

sudo apt-get install liburi-encode-perl

จากนั้นฉันก็รันสคริปต์ด้านบนในไฟล์ทดสอบที่มี:

http://foo%21asd%23asd%24%26asd%27asd%28asd%29

ผลที่ได้คือ (ฉันได้บันทึกสคริปต์เป็นfoo.pl):

$ ./foo.pl
http://foo!asd#asd$&asd'asd(asd)

3

คำตอบในเชลล์ (ส่วนใหญ่เป็น Posix):

$ input='%21%22'
$ printf "`printf "%s\n" "$input" | sed -e 's/+/ /g' -e 's/%\(..\)/\\\\x\1/g'`"
!"

คำอธิบาย:

  • -e 's/+/ /gแปลงแต่ละ+พื้นที่ (ตามที่อธิบายในบรรทัดฐาน url-encode)
  • -e 's/%\(..\)/\\\\x\1/g'เปลี่ยนแต่ละใน%XX \\xXXสังเกตว่าหนึ่งใน\จะถูกลบออกโดยอ้างกฎ
  • printf ด้านในอยู่ตรงนั้นเพื่อส่งผ่านอินพุตไปยัง sed เราอาจแทนที่ด้วยกลไกอื่น ๆ
  • printf ด้านนอกตีความ\\xXXลำดับและแสดงผลลัพธ์

แก้ไข:

เนื่องจาก%ควรตีความใน URL เสมอจึงเป็นไปได้ที่จะทำให้คำตอบนี้ง่ายขึ้น นอกจากนี้ฉันคิดว่ามันสะอาดกว่าที่จะใช้xargsแทนbackquotes (ขอบคุณ @josch)

$ input='%21%22+%25'
$ printf "%s\n" "$input" | sed -e 's/+/ /g; s/%/\\x/g' | xargs -0 printf
!" %

น่าเสียดายที่ (ตามที่ @ josch สังเกตเห็น) ไม่มีวิธีแก้ปัญหาเหล่านี้ที่สอดคล้องกับ Posix เนื่องจาก\xลำดับ escape ไม่ได้กำหนดไว้ใน Posix


ยินดีต้อนรับสู่ U&L บางทีคุณสามารถอธิบายคำตอบนี้และวิธีการทำงาน โดยทั่วไปเราต้องการคำตอบของเราในรูปแบบที่ยาวพร้อมรายละเอียดไม่ใช่แค่ตัวอย่างโค้ด
slm

ฉันชอบคำตอบนี้เพราะมันครอบคลุมพกพาได้และไม่ต้องการโปรแกรมภายนอกที่หนักกว่าเช่น Perl หรือ Python ทำงานได้ดีสำหรับฉัน
Steve Wills

1
ทางออกที่ดี ... | sed 's/+/ /g;s/%\(..\)/\\\\x\1/g'และแม้กระทั่งสั้นและชาญฉลาด: -eตัวเลือกที่สามารถละเว้นที่นี่ในความเป็นจริง ...
SyntaxError

1
@josch คุณถูกต้องprintfมันเป็นระบบในตัวdashและไม่รู้จักการ\xหลบหนี คุณสามารถใช้/usr/bin/printfแทนprintfเพื่อให้มันทำงานได้ โดยปกติแล้วคุณควรจะสามารถใช้งานcommand printfได้ แต่ดูเหมือนจะไม่ทำงานอย่างที่ควรจะเป็น มันยังคงใช้ในตัว
Jérôme Pouiller

1
@Jezz สนับสนุนอย่างแท้จริงสำหรับการ\xหลบหนีไม่ได้เป็นส่วนหนึ่งของ POSIX: pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html ระหว่างการทดสอบของฉันฉันเห็นปัญหาอื่น คุณอาจต้องการแทนที่..regex ของคุณ[a-zA-Z0-9][a-zA-Z0-9]เพราะมิฉะนั้นอินพุตเช่น '%%%' จะล้มเหลว ฉันยังเพิ่มs/%/%%/gในตอนท้ายเพื่อให้แน่ใจว่าจะหลบหนีร้อยละสำหรับ printf
josch

1

เชลล์เท่านั้น:

$ x='a%20%25%e3%81%82';printf "${x//\%/\\x}"
a %あ

เพิ่ม--หรือ%bเพื่อป้องกันการขัดแย้งที่ขึ้นต้นด้วยเส้นประจากการถือว่าเป็นตัวเลือก

ใน zsh ${x//%/a}เพิ่มaไปยังจุดสิ้นสุด แต่${x//\%/a}แทนที่ด้วย%a


1

นี่คือบิตที่เกี่ยวข้องจากสคริปต์อื่น(ที่ฉันเพิ่งลงคอจากสคริปต์ดาวน์โหลด youtube.comของฉันจากคำตอบอื่น)ฉันเคยเขียนมาก่อน มันใช้sedและเชลล์เพื่อสร้าง urldecode ที่ใช้งานได้

set \! \" \# \$ \% \& \' \( \) \* \ \+ \, \/ \: \; \= \? \@ \[ \]
for c do set "$@" "'$c" "$c"; shift; done
curl -s "$url" | sed 's/\\u0026/\&/g;'"$(
    printf 's/%%%X/\\%s/g;' "$@"
)"

ฉันจะไม่สาบานเลยว่ามันจะครอบคลุม - และอันที่จริงฉันสงสัยว่ามัน - แต่มันจัดการกับ youtube อย่างแน่นอน


1

นี่คือฟังก์ชั่น BASH ที่จะทำอย่างนั้น:

function urldecode() {
        echo -ne $(echo -n "$1" | sed -E "s/%/\\\\x/g")
}

ทำงานได้อย่างมีเสน่ห์
AbdElraouf Sabri

0

โซลูชันอื่นที่ใช้ทับทิม (คำตอบของงูหลามที่ยอมรับไม่ได้ผลสำหรับฉัน)

alias urldecode='ruby -e "require \"cgi\"; puts CGI.unescape(ARGV[0])"'
alias urlencode='ruby -e "require \"cgi\"; puts CGI.escape(ARGV[0])"'

ตัวอย่าง

$ urldecode 'q+werty%3D%2F%3B'
q werty=/;

$ urlencode 'q werty=/;'
q+werty%3D%2F%3B
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.