मैं एक Slice
को गतिशील रूप से परिभाषित करना चाहता हूं, जो या तो आगे या पीछे के सूचकांक पर आधारित हो सकता है (इस पर निर्भर करता है कि इसकी प्रारंभिक स्थिति सकारात्मक या नकारात्मक संख्या के रूप में दी गई है)।
मैं https://play.nim-lang.org/ पर चीज़ें आज़मा रहा हूं
मैंने एक संघ प्रकार की कोशिश की:
type mySlice = Slice[BackwardsIndex] | Slice[int]
var sl: mySlice
let s = "1234567890"
let bcStart = 3
let bcLen = 3
if bcLen < 0:
sl = (bcStart-1)..<(bcStart+bcLen-1)
else:
sl = ^(bcStart+bcLen-1)..^(bcStart)
echo s[sl]
यह /usercode/in.nim(2, 5) Error: invalid type: 'mySlice' for var
के साथ विफल हो जाता है।
मैंने कोशिश की
let s = "1234567890"
let bcStart = 3
let bcLen = 3
if bcLen < 0:
let sl = (bcStart-1)..<(bcStart+bcLen-1)
else:
let sl = ^(bcStart+bcLen-1)..^(bcStart)
echo s[sl]
और यह इस प्रकार विफल रहता है:
/usercode/in.nim(5, 7) Hint: 'sl' is declared but not used [XDeclaredButNotUsed]
/usercode/in.nim(7, 7) Hint: 'sl' is declared but not used [XDeclaredButNotUsed]
/usercode/in.nim(8, 8) Error: undeclared identifier: 'sl'
और मैंने निम्नलिखित की भी कोशिश की:
let s = "1234567890"
let bcStart = 3
let bcLen = 3
let sl =
if bcLen < 0:
(bcStart-1)..<(bcStart+bcLen-1)
else:
^(bcStart+bcLen-1)..^(bcStart)
echo s[sl]
असफल होने का एक अलग तरीका के साथ:
/usercode/in.nim(8, 23) Error: type mismatch: got <HSlice[system.BackwardsIndex, system.BackwardsIndex]> but expected 'HSlice[system.int, system.int]'
वे विफलताएं क्यों हैं, और मुझे कैसे करना चाहिए?
संपादित करें (09/09/2020) वांछित एपीआई
मेरा उपयोग मामला उससे अधिक जटिल है, लेकिन यह एक कमांड-लाइन प्रोग्राम के बराबर है जो तर्क के रूप में एक इनपुट टेक्स्ट, एक "बारकोड" और एक बारकोड प्रारंभ स्थिति लेता है, और यह बताता है कि बारकोड इनपुट टेक्स्ट में मौजूद है या नहीं। निर्दिष्ट स्थिति। यदि स्थिति को ऋणात्मक पूर्णांक के रूप में दिया जाता है, तो इसका अर्थ है कि हम अंत से एक स्थिति निर्दिष्ट करते हैं।
मेरे पास उम्मीद के मुताबिक कुछ काम कर रहा है:
$ cat src/test.nim
import docopt
from strutils import parseInt
# https://github.com/docopt/docopt.nim
const doc = """
Usage:
test -t <input_text> -b <barcode> -s <barcode_start>
-h --help Show this help message and exit.
-t --input_text <input_text> Text in which to search for the barcode.
-b --barcode <barcode> Barcode to search.
-s --barcode_start <barcode_start> Position at which the barcode starts (1-based), negative if from end.
"""
proc match_text(inText: string, barcode: string, bcStart: int): bool =
var
bcSeq: string
bcLen: int = barcode.len
if bcStart < 0:
bcSeq = inText[^(bcLen - bcStart - 1)..^(-bcStart)]
else:
bcSeq = inText[(bcStart-1)..<(bcStart + bcLen - 1)]
if bcSeq == barcode:
result = true
else:
result = false
when isMainModule:
let args = docopt(doc)
var
barcode: string
inText: string
bcStart: int
for opt, val in args.pairs():
case opt
of "-t", "--input_text":
inText = $args[opt]
of "-b", "--barcode":
barcode = $args[opt]
of "-s", "--barcode_start":
bcStart = parseInt($val)
else:
echo "Unknown option" & opt
quit(QuitFailure)
if match_text(inText, barcode, bcStart):
echo "Matches"
else:
echo "Doesn't match"
निर्माण का कार्य:
$ nimble build
# [successful build output]
परीक्षण कार्य:
$ ./bin/test -t aacgttb -b aa -s 1
Matches
$ ./bin/test -t aacgttb -b aa -s 2
Doesn't match
$ ./bin/test -t aacgttb -b tt -s -1
Doesn't match
$ ./bin/test -t aacgttb -b tt -s -2
Matches
हालांकि, मेरे वास्तविक अनुप्रयोग में, मैं पाठ के विभिन्न टुकड़ों में एक ही स्लाइसिंग का कई बार पुन: उपयोग कर रहा हूं, इसलिए मैं एक Slice
ऑब्जेक्ट को परिभाषित करना चाहता हूं जिसे मैं बार-बार कंप्यूटिंग के बजाय पुन: उपयोग कर सकता हूं टुकड़ा "इन-प्लेस"।
2 जवाब
सभी मुद्दे इस तथ्य से संबंधित हैं कि आपका प्रकार एक Type Class< है /ए>. यह एक छद्म प्रकार है जिसका उपयोग केवल संकलन समय पर proc अधिभार (या is
ऑपरेटर के लिए) के पैरामीटर के रूप में किया जा सकता है। विशेष रूप से इसे var
(आपके द्वारा रिपोर्ट की गई पहली त्रुटि) को असाइन नहीं किया जा सकता है और इसे रन टाइम पर गतिशील रूप से उपयोग नहीं किया जा सकता है।
आपको मिलने वाली अन्य 2 त्रुटियां 1 के कारण हैं) तथ्य यह है कि s1
अगर दायरे से बाहर परिभाषित नहीं है। 2) तथ्य यह है कि संकलक s1
के लिए एक अद्वितीय प्रकार चाहता है (यह पहले से प्रकार का अनुमान लगाता है और फिर अन्य खंड के लिए लागू होता है)।
ऑब्जेक्ट वेरिएंट (सम प्रकार, निम में बीजगणितीय डेटा प्रकार भी ; शब्दावली यूनियन प्रकार अक्सर निम में उपयोग नहीं किया जाता है) आमतौर पर गतिशील को लागू करने का सबसे सीधा तरीका है निम में प्रकार (क्लासिक उदाहरण JsonNode है)।
संपादित करें: वांछित एपीआई पर
चूंकि "स्लाइस" के पुन: उपयोग और प्रदर्शन में सुधार पर जोर दिया गया है, निम्नलिखित (यहां भी: https ://play.nim-lang.org/#ix=2wXp) का उपयोग किया जा सकता है:
type myPattern = object
barcode: string
start: int
isBackwards: bool
proc initMyPattern(barcode: string, bcStart: int): myPattern =
# no need to have a new variable for barcode.len since it is already available (not computed) for a string
# also no need to precompute last index of slice because it will not be used
if bcStart < 0:
myPattern(barcode: barcode, start: barcode.len - bcStart - 1, isBackwards: true)
else:
myPattern(barcode: barcode, start: bcStart - 1, isBackwards: false)
proc startIndex(inText: string, p: myPattern): int =
if p.isBackwards:
# this cannot be precomputed if len of inText is variable
inText.len - p.start
else:
p.start
proc match(inText: string, p: myPattern): bool =
var
i = startIndex(inText, p)
j = 0
# case where inText is not long enough to match
if i + p.barcode.len - 1 >= inText.len:
return false
# instead of computing the slice of inText (which allocates a new string), we directly iterate over indices
while j < p.barcode.len:
if p.barcode[j] != inText[i]:
return false
inc i
inc j
return true
assert "aacgttb".match initMyPattern("aa", 1)
assert not "aacgttb".match initMyPattern("aa", 2)
assert not "aacgttb".match initMyPattern("tt", -1)
assert "aacgttb".match initMyPattern("tt", -2)
assert not "aacgttb".match initMyPattern("ttbb", -2)
echo "tests successful"
टिप्पणियां:
- मुझे लगता है कि निश्चित
barcode_start
औरbarcode
को अलग-अलग ग्रंथों (संभवतः परिवर्तनीय लंबाई) के विरुद्ध कई बार मिलान करने की आवश्यकता है - एक स्ट्रिंग के "स्लाइस" की गणना करने से बचना बेहतर है, क्योंकि यह एक नई स्ट्रिंग आवंटित करता है (देखें यहां)। मुझे संदेह है कि यह स्टार्ट इंडेक्स के प्रीकंप्यूटेशन से बड़ा प्रदर्शन सुधार है।
- पिछले दो बिंदुओं से, मैच को कई बार लागू करने से पहले "संकलित" होने वाली वस्तु वास्तव में एक स्लाइस नहीं है (इसलिए नाम myPattern)
इजहार
let sl = if (bcLen >0): bcLen else: BackwardsIndex(bcLen)#Error: type mismatch!
स्थिर रूप से टाइप की गई भाषा में संकलित नहीं हो सकता है, इसलिए आपको इनहेरिटेंस या वैरिएंट का उपयोग करके sl
बॉक्स करना होगा
और फिर स्लाइस का निर्माण करते समय फिर से अनबॉक्स करें। आप ऐसा कर सकते हैं:
type
PosOrNegKind = enum
Pos,Neg
PosOrNeg = object
case kind:PosOrNegKind
of Pos: posVal:int
of Neg: negVal:int
mySlice = object
beg,fin:PosOrNeg
proc `[]`(str:string,sl:mySlice):string =
let beg = case sl.beg.kind
of Pos: sl.beg.posVal
of Neg: len(str) + sl.beg.negVal
let fin = case sl.fin.kind
of Pos: sl.fin.posVal
of Neg: len(str) + sl.fin.negVal
str[beg .. fin]
proc posOrNeg(x:int):PosOrNeg =
if (x >= 0): PosOrNeg(kind: Pos, posVal: x)
else: PosOrNeg(kind: Neg, negVal: x)
proc createSlice(beg,fin:int):mySlice =
result.beg = posOrNeg(beg)
result.fin = posOrNeg(fin)
let sl = createSlice(3,-3)
echo s[sl]# "34567"
लेकिन इस विशेष उपयोग के मामले में आपके पास मूल्य में ही प्राकृतिक भेदभावकर्ता है (चाहे int सकारात्मक या नकारात्मक है) ताकि आप बस ऐसा कर सकें:
type
MySlice = object
a,b:int
proc `--`(a,b:int):MySlice = MySlice(a: a, b: b)
proc `[]`(s:string,m:MySlice):string =
var beg = if (m.a < 0): s.len + m.a else: m.a
var fin = if (m.b < 0): s.len + m.b else: m.b
#safety checks
if fin < beg: return ""
if fin >= s.len: fin = s.len - 1
if beg < 0: beg = 0
s[beg..fin]
echo s[3 -- 5] # "345"
echo s[3 -- -2] # "345678"
echo s[-5 -- 9] # "56789"
echo s[-8 -- -2] # "2345678"
echo s[-1 -- 1] # ""
संपादित करें आप एक स्लाइस को पास करने में सक्षम होना चाहते थे जिसका उपयोग विभिन्न इनपुट स्ट्रिंग्स पर किया जा सकता था। यहां बताया गया है कि यह उपरोक्त के साथ कैसा दिखेगा:
#fixing off-by-one errors left as an exercise for the reader
proc make_slice(barcode:string,bcStart:int):mySlice=
let bcLen = barcode.len
if bcStart < 0:
(bcStart - bcLen) -- bcStart
else:
bcStart -- (bcStart + bcLen)
let sl = make_slice("abaca", -3)
for inText in @["abacus","abacadacaba","abracadabra"]:
if inText[sl] == barcode:
echo "matches"
संबंधित सवाल
नए सवाल
types
प्रकार, और प्रकार सिस्टम, का उपयोग कार्यक्रमों में अमूर्तता के स्तर को लागू करने के लिए किया जाता है।