Closed4

数字文字列(string)を数値(int)にしたい

aiiroIndyaiiroIndy

きっかけ

VerseにGetSecondsSinceEpoch関数が登場し、現実の日時を扱うことができるようになった。
そこで、西暦月日を表す8文字の数字から、西暦・月・日のそれぞれint型で分けようとしたところ、string型をint型にする関数がないことを知る。

試してみること

  • 数字1文字を数値(int型)にする
  • 2文字以上の数字を数値(int型)にする
  • 西暦月日の8文字から、西暦・月・日のそれぞれ数値(int型)に分ける
aiiroIndyaiiroIndy

数字1文字を数値(int型)にする

(a) UTF-8を使う方法
using { /Fortnite.com/Devices }
converting_a_numeric_string_to_a_number := class(creative_device):
    NumCharArr:[]char = array{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}

    OnBegin<override>():void=
        Print("NumChar.UTF8Code[] ---------------------------------------------")
        for(I -> NumChar : NumCharArr):
            if(NumInt:int = NumChar.UTF8Code[]):
                Print("NumCharArr[{I}]: NumChar={NumChar}, NumInt: {NumInt}")
            else:
                Print("NumCharArr[{I}]: NumChar={NumChar}, NumInt: Error")
# 数字1文字に対応するUTF-8コードを数値(int型)に変換する。数字ではない場合、失敗する。
(NumChar:char).UTF8Code()<transacts><decides>:int=
    var RetValueOpt:?int = false
    case(NumChar):
        '0' => set RetValueOpt = option{0x30}
        '1' => set RetValueOpt = option{0x31}
        '2' => set RetValueOpt = option{0x32}
        '3' => set RetValueOpt = option{0x33}
        '4' => set RetValueOpt = option{0x34}
        '5' => set RetValueOpt = option{0x35}
        '6' => set RetValueOpt = option{0x36}
        '7' => set RetValueOpt = option{0x37}
        '8' => set RetValueOpt = option{0x38}
        '9' => set RetValueOpt = option{0x39}
        _ => Print("UTF8Code() NumChar Error. {NumChar}")

    RetValueOpt?


[Output Log]

LogVerse: : NumChar.UTF8Code[] ---------------------------------------------
LogVerse: : NumCharArr[0]: NumChar=0, NumInt: 48
LogVerse: : NumCharArr[1]: NumChar=1, NumInt: 49
LogVerse: : NumCharArr[2]: NumChar=2, NumInt: 50
LogVerse: : NumCharArr[3]: NumChar=3, NumInt: 51
LogVerse: : NumCharArr[4]: NumChar=4, NumInt: 52
LogVerse: : NumCharArr[5]: NumChar=5, NumInt: 53
LogVerse: : NumCharArr[6]: NumChar=6, NumInt: 54
LogVerse: : NumCharArr[7]: NumChar=7, NumInt: 55
LogVerse: : NumCharArr[8]: NumChar=8, NumInt: 56
LogVerse: : NumCharArr[9]: NumChar=9, NumInt: 57

出力結果は10進数

(b) 数字を直接int型にする方法
using { /Fortnite.com/Devices }
converting_a_numeric_string_to_a_number := class(creative_device):
    NumCharArr:[]char = array{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}

    OnBegin<override>():void=
        Print("NumChar.ToInt[] ------------------------------------------------------------")
        for(I -> NumChar : NumCharArr):
            if(NumInt:int = NumChar.ToInt[]):
                Print("NumCharArr[{I}]: NumChar={NumChar}, NumInt: {NumInt}")
            else:
                Print("NumCharArr[{I}]: NumChar={NumChar}, NumInt: Error")
# 数字1文字を数値(int型)に変換する。数字ではない場合、失敗する。
(NumChar:char).ToInt()<transacts><decides>:int=
    var RetValueOpt:?int = false
    case(NumChar):
        '0' => set RetValueOpt = option{0}
        '1' => set RetValueOpt = option{1}
        '2' => set RetValueOpt = option{2}
        '3' => set RetValueOpt = option{3}
        '4' => set RetValueOpt = option{4}
        '5' => set RetValueOpt = option{5}
        '6' => set RetValueOpt = option{6}
        '7' => set RetValueOpt = option{7}
        '8' => set RetValueOpt = option{8}
        '9' => set RetValueOpt = option{9}
        _ => Print("ToInt() NumChar Error. {NumChar}")

    RetValueOpt?



[Output Log]

LogVerse: : NumChar.ToInt[] ----------------------------------------------
LogVerse: : NumCharArr[0]: NumChar=0, NumInt: 0
LogVerse: : NumCharArr[1]: NumChar=1, NumInt: 1
LogVerse: : NumCharArr[2]: NumChar=2, NumInt: 2
LogVerse: : NumCharArr[3]: NumChar=3, NumInt: 3
LogVerse: : NumCharArr[4]: NumChar=4, NumInt: 4
LogVerse: : NumCharArr[5]: NumChar=5, NumInt: 5
LogVerse: : NumCharArr[6]: NumChar=6, NumInt: 6
LogVerse: : NumCharArr[7]: NumChar=7, NumInt: 7
LogVerse: : NumCharArr[8]: NumChar=8, NumInt: 8
LogVerse: : NumCharArr[9]: NumChar=9, NumInt: 9
aiiroIndyaiiroIndy

2文字以上の数字を数値(int型)にする ✅UTF-8を使った方法

using { /Fortnite.com/Devices }
converting_a_numeric_string_to_a_number := class(creative_device):

    OnBegin<override>():void=
        NumTextArr:[]string = array:
            "0"
            "1"
            "-1"
            "123"
            "-123"
    
        for(I -> NumText : NumTextArr):
            Print("NumText.ToInt[] ----------------------------------------------")
            if(NumInt := NumText.ToInt[]):
                Print("NumTextArr[{I}]: NumText={NumText}, NumInt: {NumInt}")
            else:
                Print("NumTextArr[{I}]: NumText={NumText}, NumInt: Error")
# 文字列を数値に変換する。文字列が不適当な場合、失敗する。
(NumText:string).ToInt()<transacts><decides>:int=
    var RetValueOpt:?int = false
    var IsNegative:logic = false
    var Result:int = 0
    for(I := 0..NumText.Length-1, Char := NumText[I]):
        if(I = 0, Char = '-'):
            set IsNegative = true

        else:         
            CharCode := Char.UTF8Code[]
            set Result = Result * 10 + (CharCode - 0x30)
            Print("NumText={NumText}, NumText[{I}]={Char}, CharCode={CharCode}, 0x30={0x30}, Result={Result}")

    if(IsNegative?):
        set RetValueOpt = option{-Result}

    else:
        set RetValueOpt = option{Result}

    RetValueOpt?

# 数字1文字に対応するUTF-8コードを数値(int型)に変換する。数字ではない場合、失敗する。
(NumChar:char).UTF8Code()<transacts><decides>:int=
    var RetValueOpt:?int = false
    case(NumChar):
        '0' => set RetValueOpt = option{0x30}
        '1' => set RetValueOpt = option{0x31}
        '2' => set RetValueOpt = option{0x32}
        '3' => set RetValueOpt = option{0x33}
        '4' => set RetValueOpt = option{0x34}
        '5' => set RetValueOpt = option{0x35}
        '6' => set RetValueOpt = option{0x36}
        '7' => set RetValueOpt = option{0x37}
        '8' => set RetValueOpt = option{0x38}
        '9' => set RetValueOpt = option{0x39}
        _ => Print("UTF8Code() NumChar Error. {NumChar}")

    RetValueOpt?

Verseではchar型-char型(例: '1'-'0')ができないため、ToInt()で「CharCode - 0x30」を行っている。
(参考)
https://teratail.com/questions/27934



[Output Log]

LogVerse: : NumText.ToInt[] ----------------------------------------------
LogVerse: : NumText=0, NumText[0]=0, CharCode=48, 0x30=48, Result=0
LogVerse: : NumTextArr[0]: NumText=0, NumInt: 0
LogVerse: : NumText.ToInt[] ----------------------------------------------
LogVerse: : NumText=1, NumText[0]=1, CharCode=49, 0x30=48, Result=1
LogVerse: : NumTextArr[1]: NumText=1, NumInt: 1
LogVerse: : NumText.ToInt[] ----------------------------------------------
LogVerse: : NumText=-1, NumText[1]=1, CharCode=49, 0x30=48, Result=1
LogVerse: : NumTextArr[2]: NumText=-1, NumInt: -1
LogVerse: : NumText.ToInt[] ----------------------------------------------
LogVerse: : NumText=123, NumText[0]=1, CharCode=49, 0x30=48, Result=1
LogVerse: : NumText=123, NumText[1]=2, CharCode=50, 0x30=48, Result=12
LogVerse: : NumText=123, NumText[2]=3, CharCode=51, 0x30=48, Result=123
LogVerse: : NumTextArr[3]: NumText=123, NumInt: 123
LogVerse: : NumText.ToInt[] ----------------------------------------------
LogVerse: : NumText=-123, NumText[1]=1, CharCode=49, 0x30=48, Result=1
LogVerse: : NumText=-123, NumText[2]=2, CharCode=50, 0x30=48, Result=12
LogVerse: : NumText=-123, NumText[3]=3, CharCode=51, 0x30=48, Result=123
LogVerse: : NumTextArr[4]: NumText=-123, NumInt: -123


✅UTF-8を使わない方法
for(I -> NumText : NumTextArr):
    Print("NumText.ToInt[] ----------------------------------------------")
    if(NumInt := NumText.ToInt_2[]):
        Print("NumTextArr[{I}]: NumText={NumText}, NumInt: {NumInt}")
    else:
        Print("NumTextArr[{I}]: NumText={NumText}, NumInt: Error")
# 文字列を数値に変換する。文字列が不適当な場合、失敗する。
(NumText:string).ToInt_2()<transacts><decides>:int=
    var RetValueOpt:?int = false
    var IsNegative:logic = false
    var Result:int = 0
    for(I := 0..NumText.Length-1, Char := NumText[I]):
        if(I = 0, Char = '-'):
            set IsNegative = true

        else:         
            CharNumber := Char.ToInt[]
            set Result = Result * 10 + CharNumber
            Print("NumText={NumText}, NumText[{I}]={Char}, CharNumber={CharNumber}, Result={Result}")

    if(IsNegative?):
        set RetValueOpt = option{-Result}

    else:
        set RetValueOpt = option{Result}

    RetValueOpt?

# 数字1文字を数値(int型)に変換する。数字ではない場合、失敗する。
(NumChar:char).ToInt()<transacts><decides>:int=
    var RetValueOpt:?int = false
    case(NumChar):
        '0' => set RetValueOpt = option{0}
        '1' => set RetValueOpt = option{1}
        '2' => set RetValueOpt = option{2}
        '3' => set RetValueOpt = option{3}
        '4' => set RetValueOpt = option{4}
        '5' => set RetValueOpt = option{5}
        '6' => set RetValueOpt = option{6}
        '7' => set RetValueOpt = option{7}
        '8' => set RetValueOpt = option{8}
        '9' => set RetValueOpt = option{9}
        _ => Print("ToInt() NumChar Error. {NumChar}")

    RetValueOpt?



[Output Log]
結果は同じ

LogVerse: : NumText.ToInt[] ----------------------------------------------
LogVerse: : NumText=0, NumText[0]=0, CharNumber=0, Result=0
LogVerse: : NumTextArr[0]: NumText=0, NumInt: 0
LogVerse: : NumText.ToInt[] ----------------------------------------------
LogVerse: : NumText=1, NumText[0]=1, CharNumber=1, Result=1
LogVerse: : NumTextArr[1]: NumText=1, NumInt: 1
LogVerse: : NumText.ToInt[] ----------------------------------------------
LogVerse: : NumText=-1, NumText[1]=1, CharNumber=1, Result=1
LogVerse: : NumTextArr[2]: NumText=-1, NumInt: -1
LogVerse: : NumText.ToInt[] ----------------------------------------------
LogVerse: : NumText=123, NumText[0]=1, CharNumber=1, Result=1
LogVerse: : NumText=123, NumText[1]=2, CharNumber=2, Result=12
LogVerse: : NumText=123, NumText[2]=3, CharNumber=3, Result=123
LogVerse: : NumTextArr[3]: NumText=123, NumInt: 123
LogVerse: : NumText.ToInt[] ----------------------------------------------
LogVerse: : NumText=-123, NumText[1]=1, CharNumber=1, Result=1
LogVerse: : NumText=-123, NumText[2]=2, CharNumber=2, Result=12
LogVerse: : NumText=-123, NumText[3]=3, CharNumber=3, Result=123
LogVerse: : NumTextArr[4]: NumText=-123, NumInt: -123
aiiroIndyaiiroIndy

西暦月日の8文字から、西暦・月・日のそれぞれ数値(int型)に分ける

現時点でVerseには日時を扱うクラスや構造体がない
あると今後も日時を扱いやすくなりそうなので まず作る

date_time_struct := struct:
    Year:int
    Month:int
    Day:int
    Hour:int
    Minute:int
    Second:int
    Millisecond:int


using { /Fortnite.com/Devices }
converting_a_numeric_string_to_a_number := class(creative_device):

    OnBegin<override>():void=
        Test("20240907")    #正常
        Test("20000101")    #正常
        Test("2024123")     #文字数が不足で失敗するケース
        Test("20240907")    #全角(Lengthが大きい)で失敗ケースするケース

    Test(DateStr:string):void=
        Print("Test({DateStr}) ----------------------------------------------")
        if(DateDT:date_time_struct = DateStr.DateStringToDateTime[]):
            Print("DateStr: {DateStr}, DateDT: [{DateDT.Year}/{DateDT.Month}/{DateDT.Day} {DateDT.Hour}:{DateDT.Minute}:{DateDT.Second}.{DateDT.Millisecond}]")
        else:
            Print("DateStr: {DateStr}, DateDT: Error")

# 西暦月日(半角8文字)をdate_time_structに変換する。文字列が不適当な場合、失敗する。
(DateStr:string).DateStringToDateTime()<transacts><decides>:date_time_struct=
    var RetValueOpt:?date_time_struct = false
    if(DateStr.Length = 8):
        if:
            YearsStr := DateStr.Slice[0, 4]
            MonthsStr := DateStr.Slice[4, 6]
            DaysStr := DateStr.Slice[6, 8]

        then:
            if:
                YearsInt:int = YearsStr.ToInt[]
                MonthsInt:int = MonthsStr.ToInt[]
                DaysInt:int = DaysStr.ToInt[]

            then:
                set RetValueOpt = option:
                    date_time_struct:
                        Year := YearsInt
                        Month := MonthsInt
                        Day := DaysInt
                        Hour := 0  #使用しないため0を設定
                        Minute := 0  #使用しないため0を設定
                        Second := 0  #使用しないため0を設定
                        Millisecond := 0  #使用しないため0を設定

            else:
                Print("DateStringToDateTime() DateStringToInt Error. {YearsStr}, {MonthsStr}, {DaysStr}")

        else:
            Print("DateStringToDateTime() DateStr.Slice Error. {DateStr}")
    else:
        Print("DateStringToDateTime() DateStr.Length Error. {DateStr} DateStr.Length={DateStr.Length}")
                
    RetValueOpt?

文字列を数値にする

(前回の投稿「2文字以上の数字を数値(int型)にする ✅UTF-8を使った方法」と同じ)

# 文字列を数値に変換する。文字列が不適当な場合、失敗する。
(NumText:string).ToInt()<transacts><decides>:int=
    var RetValueOpt:?int = false
    var IsNegative:logic = false
    var Result:int = 0
    for(I := 0..NumText.Length-1, Char := NumText[I]):
        if(I = 0, Char = '-'):
            set IsNegative = true

        else:         
            CharCode := Char.UTF8Code[]
            set Result = Result * 10 + (CharCode - 0x30)
            Print("NumText={NumText}, NumText[{I}]={Char}, CharCode={CharCode}, 0x30={0x30}, Result={Result}")

    if(IsNegative?):
        set RetValueOpt = option{-Result}

    else:
        set RetValueOpt = option{Result}

    RetValueOpt?

# 数字1文字に対応するUTF-8コードを数値(int型)に変換する。数字ではない場合、失敗する。
(NumChar:char).UTF8Code()<transacts><decides>:int=
    var RetValueOpt:?int = false
    case(NumChar):
        '0' => set RetValueOpt = option{0x30}
        '1' => set RetValueOpt = option{0x31}
        '2' => set RetValueOpt = option{0x32}
        '3' => set RetValueOpt = option{0x33}
        '4' => set RetValueOpt = option{0x34}
        '5' => set RetValueOpt = option{0x35}
        '6' => set RetValueOpt = option{0x36}
        '7' => set RetValueOpt = option{0x37}
        '8' => set RetValueOpt = option{0x38}
        '9' => set RetValueOpt = option{0x39}
        _ => Print("UTF8Code() NumChar Error. {NumChar}")

    RetValueOpt?



[Output Log]

LogVerse: : Test(20240907) ----------------------------------------------
LogVerse: : NumText=2024, NumText[0]=2, CharCode=50, 0x30=48, Result=2
LogVerse: : NumText=2024, NumText[1]=0, CharCode=48, 0x30=48, Result=20
LogVerse: : NumText=2024, NumText[2]=2, CharCode=50, 0x30=48, Result=202
LogVerse: : NumText=2024, NumText[3]=4, CharCode=52, 0x30=48, Result=2024
LogVerse: : NumText=09, NumText[0]=0, CharCode=48, 0x30=48, Result=0
LogVerse: : NumText=09, NumText[1]=9, CharCode=57, 0x30=48, Result=9
LogVerse: : NumText=07, NumText[0]=0, CharCode=48, 0x30=48, Result=0
LogVerse: : NumText=07, NumText[1]=7, CharCode=55, 0x30=48, Result=7
LogVerse: : DateStr: 20240907, DateDT: [2024/9/7 0:0:0.0]
LogVerse: : Test(20000101) ----------------------------------------------
LogVerse: : NumText=2000, NumText[0]=2, CharCode=50, 0x30=48, Result=2
LogVerse: : NumText=2000, NumText[1]=0, CharCode=48, 0x30=48, Result=20
LogVerse: : NumText=2000, NumText[2]=0, CharCode=48, 0x30=48, Result=200
LogVerse: : NumText=2000, NumText[3]=0, CharCode=48, 0x30=48, Result=2000
LogVerse: : NumText=01, NumText[0]=0, CharCode=48, 0x30=48, Result=0
LogVerse: : NumText=01, NumText[1]=1, CharCode=49, 0x30=48, Result=1
LogVerse: : NumText=01, NumText[0]=0, CharCode=48, 0x30=48, Result=0
LogVerse: : NumText=01, NumText[1]=1, CharCode=49, 0x30=48, Result=1
LogVerse: : DateStr: 20000101, DateDT: [2000/1/1 0:0:0.0]
LogVerse: : Test(2024123) ----------------------------------------------
LogVerse: : (Rolling Back) DateStringToDateTime() DateStr.Length Error. 2024123 DateStr.Length=7
LogVerse: : DateStr: 2024123, DateDT: Error
LogVerse: : Test(20240907) ----------------------------------------------
LogVerse: : (Rolling Back) DateStringToDateTime() DateStr.Length Error. 20240907 DateStr.Length=24
LogVerse: : DateStr: 20240907, DateDT: Error
このスクラップは2024/09/07にクローズされました