سؤال

أبحث عن تعادل SCANF (). حاولت مع التعليمات البرمجية التالية:

  1 package main
  2 
  3 import (
  4     "scanner"
  5     "os"
  6     "fmt"
  7 )
  8 
  9 func main() {
 10     var s scanner.Scanner
 11     s.Init(os.Stdin)
 12     s.Mode = scanner.ScanInts
 13     tok := s.Scan()
 14     for tok != scanner.EOF {
 15         fmt.Printf("%d ", tok)
 16         tok = s.Scan()
 17     }
 18     fmt.Println()
 19 }

قمت بتشغيله بإدخال نص من النص مع مجموعة من الأعداد الصحيحة. لكنه دائما إخراج -3 -3 ...

وكيفية مسح خط يتكون من سلسلة وبعض الأعداد الصحيحة؟ تغيير الوضع كلما صادف نوع بيانات جديد؟

وثائق الحزمة:

الحزمة الماسح الضوئي

الماسح الضوئي للأغراض العامة للنص المشفر UTF-8.

ولكن يبدو أن الماسح الضوئي ليس للاستخدام العام.

رمز محدث:

func main() {
    n := scanf()
    fmt.Println(n)
    fmt.Println(len(n))
}

func scanf() []int {
    nums := new(vector.IntVector)
    reader := bufio.NewReader(os.Stdin)
    str, err := reader.ReadString('\n')
    for err != os.EOF {
        fields := strings.Fields(str)
        for _, f := range fields {
            i, _ := strconv.Atoi(f)
            nums.Push(i)
        }   
        str, err = reader.ReadString('\n')
    }   
    r := make([]int, nums.Len())
    for i := 0; i < nums.Len(); i++ {
        r[i] = nums.At(i)
    }   
    return r
}

نسخة محسنة:

package main

import (
    "bufio"
    "os"
    "io"
    "fmt"
    "strings"
    "strconv"
    "container/vector"
)

func main() {
    n := fscanf(os.Stdin)
    fmt.Println(len(n), n)
}

func fscanf(in io.Reader) []int {
    var nums vector.IntVector
    reader := bufio.NewReader(in)
    str, err := reader.ReadString('\n')
    for err != os.EOF {
        fields := strings.Fields(str)
        for _, f := range fields {
            if i, err := strconv.Atoi(f); err == nil {
                nums.Push(i)
            }   
        }   
        str, err = reader.ReadString('\n')
    }   
    return nums
}
هل كانت مفيدة؟

المحلول

كان الرمز المحدث الخاص بك هو أسهل بكثير الترجمة دون أرقام السطر، لكنه كان يفتقد عبارات الحزمة والاستيراد.

النظر في التعليمات البرمجية الخاصة بك، لاحظت بعض الأشياء. إليك الإصدار المنقح الخاص بي من التعليمات البرمجية الخاصة بك.

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strconv"
    "strings"
    "container/vector"
)

func main() {
    n := scanf(os.Stdin)
    fmt.Println()
    fmt.Println(len(n), n)
}

func scanf(in io.Reader) []int {
    var nums vector.IntVector
    rd := bufio.NewReader(os.Stdin)
    str, err := rd.ReadString('\n')
    for err != os.EOF {
        fields := strings.Fields(str)
        for _, f := range fields {
            if i, err := strconv.Atoi(f); err == nil {
                nums.Push(i)
            }
        }
        str, err = rd.ReadString('\n')
    }
    return nums
}

قد أرغب في استخدام أي ملف إدخال ل scanf(), ، ليس مجرد Stdin; scanf() يأخذ io.Reader كمعلمة.

انت كتبت: nums := new(vector.IntVector), ، أين type IntVector []int. وبعد هذا يخصص مرجع شريحة عددا صحيحا اسمه nums وتهيئة ذلك إلى الصفر، ثم new() وظيفة تخصيص إشارة شريحة عدد صحيح وتهيئةها إلى الصفر، ثم تعينها nums. وبعد كتبت: var nums vector.IntVector, ، والتي تتجنب التكرار عن طريق تخصيص إشارة شريحة عدد صحيح باسم nums وتهيئة ذلك إلى الصفر.

أنت لم تحقق err القيمة ل strconv.Atoi(), ، مما يعني أن إدخال غير صالح تم تحويله إلى قيمة صفرية؛ أنا تخطي ذلك.

لنسخ من المتجه إلى شريحة جديدة وإرجاع الشريحة، كتبت:

r := make([]int, nums.Len())
for i := 0; i < nums.Len(); i++ {
    r[i] = nums.At(i)
}
return r

أولا، ببساطة استبدال ذلك مع ما يعادلها، IntVector.Data() طريقة: return nums.Data(). وبعد بعد ذلك، استفادت من حقيقة ذلك type IntVector []int وتجنب التخصيص والنسخ عن طريق استبدال ذلك ب: return nums.

نصائح أخرى

على الرغم من أنه يمكن استخدامه لأشياء أخرى، تم تصميم حزمة الماسح الضوئي لمسح نص البرنامج. Ints (-123)، chars ('c')، السلاسل ("str")، وما إلى ذلك تذهب أنواع رمزية اللغة.

package main

import (
    "fmt"
    "os"
    "scanner"
    "strconv"
)

func main() {
    var s scanner.Scanner
    s.Init(os.Stdin)
    s.Error = func(s *scanner.Scanner, msg string) { fmt.Println("scan error", msg) }
    s.Mode = scanner.ScanInts | scanner.ScanStrings | scanner.ScanRawStrings
    for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
        txt := s.TokenText()
        fmt.Print("token:", tok, "text:", txt)
        switch tok {
        case scanner.Int:
            si, err := strconv.Atoi64(txt)
            if err == nil {
                fmt.Print(" integer: ", si)
            }
        case scanner.String, scanner.RawString:
            fmt.Print(" string: ", txt)
        default:
            if tok >= 0 {
                fmt.Print(" unicode: ", "rune = ", tok)
            } else {
                fmt.Print(" ERROR")
            }
        }
        fmt.Println()
    }
}

يقرأ هذا المثال دائما في سطر في وقت واحد وإرجاع السطر بأكمله كسلسلة. إذا كنت ترغب في تحليل قيم محددة منه، يمكنك.

package main

import (
    "fmt"
    "bufio"
    "os"
    "strings"
)

func main() {
    value :=    Input("Please enter a value: ")
    trimmed := strings.TrimSpace(value)
    fmt.Printf("Hello %s!\n", trimmed)
}

func Input(str string) string { 
        print(str) 
        reader := bufio.NewReader(os.Stdin) 
        input, _ := reader.ReadString('\n') 
        return input 
}

في تعليق لأحد إجاباتي، قلت:

من مواصفات اللغة: "عندما يتم تخصيص الذاكرة لتخزين قيمة، إما من خلال إعلان أو إجراء () أو إجراء () أو جديد ()، ولا يتم توفير تهيئة صريحة، يتم إعطاء الذاكرة تهيئة افتراضية". ثم ما هي نقطة جديدة ()؟

إذا جرينا:

package main

import ("fmt")

func main() {
    var i int
    var j *int
    fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j)
    j = new(int)
    fmt.Println("i (a value) = ", i, "; j (a pointer) = ", j, "; *j (a value) = ", *j)
}

الإعلان var i int يخصص الذاكرة لتخزين قيمة عدد صحيح وتهيئة القيمة إلى الصفر. الإعلان var j *int يخصص الذاكرة لتخزين مؤشر إلى قيمة عدد صحيح وتهيئة المؤشر إلى الصفر (مؤشر NIL)؛ لا يتم تخصيص أي ذاكرة لتخزين قيمة عدد صحيح. نرى إخراج البرنامج على غرار:

i (a value) =  0 ; j (a pointer) =  <nil>

وظيفة المدمج new يأخذ نوع T وإرجاع قيمة النوع *T. وبعد تتم تهيئة الذاكرة إلى قيم صفر. البيان j = new(int) يخصص الذاكرة لتخزين قيمة عدد صحيح وتهيئة القيمة إلى الصفر، ثم يخزن مؤشر إلى هذه القيمة الصحيحة في J. نرى إخراج البرنامج على غرار:

i (a value) =  0 ; j (a pointer) =  0x7fcf913a90f0 ; *j (a value) =  0

أضاف أحدث إصدار من الذهاب (2010-05-27) وظيفتين ل fmt صفقة: Scan() و Scanln(). وبعد انهم لا يأخذون أي سلسلة نمط. مثل في C، ولكن يتحقق من نوع الحجج بدلا من ذلك.

package main

import (
   "fmt"
   "os"
   "container/vector"
)

func main() {
    numbers := new(vector.IntVector)
    var number int
    n, err := fmt.Scan(os.Stdin, &number)
    for n == 1 && err == nil {
       numbers.Push(number)
       n, err = fmt.Scan(os.Stdin, &number)
    }
    fmt.Printf("%v\n", numbers.Data())
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top