Phân tích cú pháp chuỗi Python


9

Thách thức là phân tích một chuỗi như Python và in nội dung của chuỗi.

  • Đầu vào (đối số dòng lệnh hoặc stdin) : một chuỗi ký tự (ví dụ "hello") (hoặc nhiều chữ, xem nối chuỗi bằng chữ bên dưới)
  • Đầu ra (stdout) : nội dung của chuỗi (ví dụ hello)

Quy tắc phân tích chuỗi:

  • Một chuỗi ký tự được đặt trong các cặp dấu ngoặc đơn ( 'a'), dấu ngoặc kép ( "a"), dấu ngoặc kép đơn ( '''a''') hoặc dấu ngoặc kép kép ( """a"""). Lần tái xuất đầu tiên của loại trích dẫn đã mở chuỗi kết thúc chuỗi.
  • Dấu gạch chéo ngược thoát ra: \' trong một chuỗi trở thành ', \"trở thành "\\trở thành \. Bạn không cần phải thực hiện bất kỳ thoát dấu gạch chéo ngược nào khác. Dấu gạch chéo ngược không phải là một phần của chuỗi thoát vẫn là dấu gạch chéo ngược.
  • Nối chuỗi bằng chữ: Các nội dung của chuỗi ký tự chuỗi liền kề được nối. Ví dụ, "hello" 'world'trở thành helloworld.
  • Đầu vào có thể chứa các khoảng trắng không phải là một phần của bất kỳ nghĩa đen nào.
  • Bạn không cần phải hỗ trợ bất kỳ loại khoảng trắng nào khác, cả bên trong lẫn bên ngoài nghĩa đen.

Quy tắc bổ sung:

  • eval, execVà các công cụ tương tự không được phép cho phân tích cú pháp văn chương hoặc các bộ phận của nó.
  • Bạn có thể cho rằng đầu vào là hợp lệ.
  • Bạn có thể giả sử độ dài đầu vào tối đa là 1023 ký tự.

Ví dụ:

  • "hello" ' world' -> hello world
  • """\"""'\\\A""" -> """'\\A
  • ( '''"""'''"""'''""" ) (không có dấu ngoặc đơn, nhưng có dấu cách) -> """'''

Mã ngắn nhất sẽ thắng.


Là đầu ra phải là một hình thức có thể được lưu trữ, hoặc nó có đủ để in nó và được thực hiện với nó?
DavidC

@David In nó là tất cả những gì bạn cần làm.
flornquake

Vậy trong (ví dụ) "\ z", mã được yêu cầu cụ thể để xuất ra dấu gạch chéo ngược và z? Nhưng \ 'chỉ trở thành một dấu nháy đơn, ngay cả khi nó xuất hiện bên trong dấu ngoặc kép hoặc dấu ba chấm? Đúng không?
hộp bánh mì

@breadbox Chính xác.
flornquake

Mã có nên hỗ trợ chuỗi thô? Và những gì về nối chuỗi không thô và thô?
Bakuriu

Câu trả lời:


4

Perl, 54 ký tự

#!/usr/bin/perl -p
s/ |("""|'''|"|')((\\?.)*?)\1/$2/g;s/\\(["'\\])/$1/g

Ngay khi tôi đăng bài này, tôi nhận thấy rằng nó gần giống với giải pháp Ruby của Jan Dvorak. Trên thực tế, tôi hơi bối rối vì nó giống nhau đến mức nào, nhưng tôi sẽ nói "Những bộ óc vĩ đại nghĩ giống nhau" và để nó đi vào đó.

Chương trình này nêu bật một trường hợp góc kỳ lạ khi đếm các ký tự trong các tập lệnh Perl: Theo cách đọc của tôi, sự hiện diện của các dấu ngoặc đơn trong kịch bản có nghĩa là tôi cần tính -ptùy chọn là hai ký tự trong tổng số của mình. Thông thường, khi tính toán kích thước tập lệnh Perl, ký tự dấu gạch ngang ban đầu trên các tùy chọn được coi là miễn phí, với lý do là nó có thể được gói cùng với phần -egiới thiệu chương trình phù hợp ... nhưng sau đó bạn cũng phải tính đến bất kỳ lần thoát bổ sung nào bạn cần nhập tập lệnh trên dòng lệnh. Các trích dẫn đơn yêu cầu nhiều lối thoát, vì vậy để tránh hình phạt đó, tôi phải tính nó là một tập lệnh chạy từ một tập tin, và do đó tôi nhận được #!/usr/bin/perlmiễn phí, nhưng không có bất kỳ ký tự tùy chọn nào. Nó hơi khó hiểu.


2
Nếu bạn muốn khác biệt, (('|")\2{2}?)có cùng độ dài với("""|'''|"|')
Peter Taylor

3

C, 178 ký tự

char*p,*q,b[1024];d;main(t){for(p=q=gets(b);*p=*q++;)
d?*p==92&!(*q-*p&&*q-34&&*q-39)?*p++=*q++:*p-d||t&&*q-d|q[1]-d?++p:
(d=0,q+=2*t):*p-32?d=*p,t=*q==d&q[1]==d,q+=2*t:0;puts(b);}

Đây là một trong những giải pháp C trong đó mọi thứ được thực hiện trong một băng đảng chuỗi nhà điều hành.

Chương trình hoạt động bằng cách sao chép các ký tự trở lại vào cùng một bộ đệm, ghi đè lên các siêu ký tự. dgiữ dấu phân cách khi bên trong chuỗi và tđúng nếu dấu phân cách là dấu ngoặc kép.


Tôi nghĩ bạn cần bao gồm một sự gia tăng thêm có điều kiện của biến điều khiển vòng lặp. Đối với 'foo \\' bar ', nó cung cấp cho foo \ ar', có vẻ như nó thay thế \ bằng \, nhưng sau đó tiếp tục phân tích cú pháp với \ mới được nhập, xem mã thông báo tiếp theo là \ '.
manatwork

Trên thực tế, ví dụ đó là đầu vào không hợp lệ. 'foo\\'đề cập đến chuỗi foo \, sau đó được theo sau bởi một ký tự không phải là khoảng trắng cũng không phải là dấu phân cách chuỗi.
hộp bánh mì

Giáo sư. Tôi đọc sai quy tắc đó. Sau đó, tất nhiên mã của bạn là chính xác.
manatwork

3

Hồng ngọc 74 73 ký tự

puts gets.gsub(/('''|"""|'|")((\\?.)*?)\1|./,'\2').gsub /\\([\\'"])/,'\1'

Cốt lõi ở đây là hai regex: Cái đầu tiên xác định ranh giới chuỗi và chỉ chọn nội dung. Sự thay đổi là ở đó để loại bỏ tất cả mọi thứ không bên trong chuỗi, và nó cũng giảm các chuỗi không được tiết lộ.Dấu gạch chéo ngược được coi là sở hữu tùy chọn theo sau bởi bất cứ điều gì. Như vậyVì công cụ regex sẽ không quay lại (\\?.)các đầu vào hợp lệ (cảm ơn @breadbox), một dấu gạch chéo ngược duy nhất không thể phù hợp ở đó. Báo giá được xử lý thông qua sự lặp lại lười biếng. Regex thứ hai sau đó loại bỏ dấu gạch chéo ngược trước mỗi ký tự có thể thoát được. Regex phụ thuộc vào động cơ để luôn luôn chọn phương án ngoài cùng bên trái trước.

Tôi cũng đã xem xét một cách tiếp cận máy trạng thái, nhưng nó khá lớn (19 lớp x 4 ký tự) so với giải pháp regex. Tôi vẫn có thể đăng máy trạng thái nếu có ai quan tâm.


Một trục trặc nhỏ với phương pháp này: 'foo \' bar 'trở thành foo \ thay vì' foo \ 'bar'.
manatwork

@manatwork điều này là chính xác, trừ khi một cái gì đó đã bị mất trong định dạng. Dấu gạch chéo đầu tiên thoát khỏi cái thứ hai. 'foo\\'là chuỗi đầu tiên và bar'nằm ngoài ngữ cảnh chuỗi khi đầu vào là'foo\\'bar'
John Dvorak

Giáo sư. Không biết làm thế nào tôi tính toán nó sớm hơn. Tất nhiên là đúng. Lấy làm tiếc.
manatwork

Khi tôi cố chạy cái này, tôi nhận được một thông báo lỗi: "lồng nhau *? + Trong regrec". Có một số phiên bản tối thiểu hoặc cờ thời gian chạy mà tôi cần?
hộp bánh mì

@breadbox Tôi chưa kiểm tra các phiên bản khác, nhưng tôi đang chạy ruby ​​1.9.3 (JRuby 1.7.2). Tôi có nên giả sử 1.9.3 ít nhất và chỉnh sửa nó trong?
John Dvorak
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.