ทดสอบว่าสตริงเป็นจำนวนเต็มที่ถูกต้องหรือไม่


117

ฉันกำลังพยายามทำบางสิ่งที่ธรรมดาพอ: แยกวิเคราะห์อินพุตของผู้ใช้ในเชลล์สคริปต์ หากผู้ใช้ระบุจำนวนเต็มที่ถูกต้องสคริปต์จะทำสิ่งหนึ่งและถ้าไม่ถูกต้องสคริปต์จะทำอย่างอื่น ปัญหาคือฉันไม่พบวิธีที่ง่าย (และสง่างามพอสมควร) ในการทำสิ่งนี้ - ฉันไม่ต้องการแยกมันออกจากถ่านโดยใช้ถ่าน

ฉันรู้ว่ามันต้องง่าย แต่ฉันไม่รู้วิธี ฉันสามารถทำได้ในหลายสิบภาษา แต่ไม่ใช่ BASH!

ในการวิจัยของฉันฉันพบสิ่งนี้:

นิพจน์ทั่วไปเพื่อทดสอบว่าสตริงประกอบด้วยจำนวนจริงที่ถูกต้องในฐาน 10 หรือไม่

และมีคำตอบในนั้นที่พูดถึง regex แต่เท่าที่ฉันรู้นั่นคือฟังก์ชันที่มีอยู่ใน C (อื่น ๆ ) ยังคงมีสิ่งที่ดูเหมือนคำตอบที่ดีดังนั้นฉันจึงลองใช้ grep แต่ grep ไม่รู้ว่าจะทำอย่างไรกับมัน ฉันพยายาม -P ซึ่งในกล่องของฉันหมายถึงถือว่าเป็น PERL regexp - nada Dash E (-E) ไม่ทำงานเช่นกัน และไม่ได้ -F

เพื่อความชัดเจนฉันกำลังลองสิ่งนี้โดยมองหาผลลัพธ์ใด ๆ - จากตรงนั้นฉันจะแฮ็กสคริปต์เพื่อใช้ประโยชน์จากสิ่งที่ฉันได้รับ (IOW ฉันคาดหวังว่าอินพุตที่ไม่สอดคล้องจะไม่ส่งคืนอะไรเลยในขณะที่บรรทัดที่ถูกต้องซ้ำ ๆ กัน)

snafu=$(echo "$2" | grep -E "/^[-+]?(?:\.[0-9]+|(?:0|[1-9][0-9]*)(?:\.[0-9]*)?)$/")
if [ -z "$snafu" ] ;
then
   echo "Not an integer - nothing back from the grep"
else
   echo "Integer."
fi

ใครช่วยอธิบายวิธีการนี้ได้ง่ายที่สุด?

ตรงไปตรงมานี่คือการทดสอบสั้น ๆ ในความคิดของฉัน มันควรมีธงแบบนี้

if [ -I "string" ] ;
then
   echo "String is a valid integer."
else
   echo "String is not a valid integer."
fi

4
FYI: [เก่าเข้ากันได้test; [[เป็นสิ่งใหม่ของ Bash ที่มีการดำเนินการมากขึ้นและกฎการอ้างอิงที่แตกต่างกัน หากคุณตัดสินใจที่จะใช้ Bash ไปแล้วให้ไป[[(มันดีกว่ามาก) หากคุณต้องการพกพาไปยังกระสุนอื่น ๆ ให้หลีกเลี่ยงโดย[[สิ้นเชิง
ephemient

คำตอบ:


183
[[ $var =~ ^-?[0-9]+$ ]]
  • ^บ่งชี้ว่าจุดเริ่มต้นของรูปแบบการป้อนข้อมูล
  • -เป็นตัวอักษร "-"
  • ?หมายถึง "0 หรือ 1 ของก่อนหน้า ( -)"
  • +หมายถึง "1 หรือมากกว่าก่อนหน้า ( [0-9])"
  • $แสดงให้เห็นจุดสิ้นสุดของรูปแบบการป้อนข้อมูล

ดังนั้นนิพจน์ทั่วไปจึงจับคู่ตัวเลือก-(สำหรับกรณีของจำนวนลบ) ตามด้วยทศนิยมหนึ่งหลักขึ้นไป

อ้างอิง :


3
ขอบคุณอิกนาซิโอฉันจะลองอีกสักครู่ ช่วยอธิบายให้ฉันได้เรียนรู้สักหน่อยได้ไหม ฉันรวบรวมมันอ่านว่า "ที่จุดเริ่มต้นของสตริง (^) เครื่องหมายลบ (-) เป็นทางเลือก (?) ตามด้วยอักขระจำนวนเท่าใดก็ได้ระหว่างศูนย์ถึง 9 รวม" ... แล้วอะไรจะทำให้เครื่องหมาย + $ หมายความว่า? ขอบคุณ
Richard T

10
+หมายถึง "1 หรือมากกว่าก่อนหน้านี้" และ$ชี้ให้เห็นจุดสิ้นสุดของรูปแบบการป้อนข้อมูล ดังนั้น regex จึงจับคู่ตัวเลือก-ตามด้วยทศนิยมหนึ่งหลักขึ้นไป
Ignacio Vazquez-Abrams

บ่นเรื่องลิงค์ ABS
Charles Duffy

มันเป็นแทนเจนต์ แต่โปรดทราบว่าเมื่อระบุช่วงอักขระคุณจะได้ผลลัพธ์แปลก ๆ ตัวอย่างเช่น[A-z]จะไม่เพียงให้คุณA-Zและa-zแต่ยัง\ , [, ], ^, และ_ `
Doktor J

นอกจากนี้ตามการเรียงตัวอักษร ( ดูคำถาม / คำตอบที่เกี่ยวข้อง ) สิ่งที่ต้องการd[g-i]{2}ไม่เพียงdigแต่การจับคู่แต่ยังรวมdishถึงการเปรียบเทียบที่แนะนำโดยคำตอบนั้นด้วย (โดยที่shdigraph ถือเป็นอักขระเดี่ยวเรียงตามหลังh)
ดอกเตอร์ J

61

ว้าว ... มีทางออกดีๆมากมายที่นี่ !! จากวิธีแก้ปัญหาทั้งหมดข้างต้นฉันเห็นด้วยกับ @nortally ว่าการใช้-eqซับเดียวนั้นเจ๋งที่สุด

ฉันใช้ GNU bash เวอร์ชัน4.1.5(Debian) ฉันได้ตรวจสอบสิ่งนี้ใน ksh ด้วย (SunSO 5.10)

นี่คือเวอร์ชันของฉันในการตรวจสอบว่า$1เป็นจำนวนเต็มหรือไม่:

if [ "$1" -eq "$1" ] 2>/dev/null
then
    echo "$1 is an integer !!"
else
    echo "ERROR: first parameter must be an integer."
    echo $USAGE
    exit 1
fi

วิธีนี้ยังอธิบายถึงจำนวนลบซึ่งวิธีแก้ปัญหาอื่น ๆ บางส่วนจะมีผลลบที่ผิดพลาดและจะให้คำนำหน้าเป็น "+" (เช่น +30) ซึ่งเห็นได้ชัดว่าเป็นจำนวนเต็ม

ผล:

$ int_check.sh 123
123 is an integer !!

$ int_check.sh 123+
ERROR: first parameter must be an integer.

$ int_check.sh -123
-123 is an integer !!

$ int_check.sh +30
+30 is an integer !!

$ int_check.sh -123c
ERROR: first parameter must be an integer.

$ int_check.sh 123c
ERROR: first parameter must be an integer.

$ int_check.sh c123
ERROR: first parameter must be an integer.

วิธีแก้ปัญหาที่จัดทำโดย Ignacio Vazquez-Abrams นั้นเรียบร้อยมาก (ถ้าคุณชอบ regex) หลังจากอธิบายแล้ว อย่างไรก็ตามมันไม่ได้จัดการกับตัวเลขที่เป็นบวกด้วย+คำนำหน้า แต่สามารถแก้ไขได้ง่ายดังต่อไปนี้:

[[ $var =~ ^[-+]?[0-9]+$ ]]

ดี! ค่อนข้างคล้ายกับสิ่งนี้
devnull

ใช่. ก็คล้าย ๆ กัน. อย่างไรก็ตามฉันกำลังมองหาโซลูชันซับสำหรับคำสั่ง "if" ฉันคิดว่าฉันไม่จำเป็นต้องเรียกใช้ฟังก์ชันนี้จริงๆ นอกจากนี้ฉันยังเห็นว่าการเปลี่ยนเส้นทางของ stderr เป็น stdout ในฟังก์ชัน เมื่อฉันลองข้อความ stderr "นิพจน์จำนวนเต็มที่คาดหวัง" ปรากฏขึ้นซึ่งไม่เป็นที่ต้องการสำหรับฉัน
Peter Ho

ขอบคุณ! ฉันจะเรียกสิ่งนี้ว่าง่ายและสง่างาม
Ezra Nugroho

2
มีความแตกต่างที่น่าทึ่งระหว่างโซลูชันของคุณและ regex หนึ่ง: ขนาดของจำนวนเต็มจะถูกตรวจสอบตามขีด จำกัด bash (บนคอมพิวเตอร์ของฉันคือ 64 บิต) ขีด จำกัด นี้ไม่ถึงโซลูชัน regexp ดังนั้นการแก้ปัญหาของคุณจะล้มเหลวในจำนวนที่มากกว่า 9223372036854775807 บนคอมพิวเตอร์ 64 บิต
vaab

2
ขณะที่ผมเพิ่งค้นพบมีบางประการ
Kyle Strand

28

Latecomer มางานปาร์ตี้ที่นี่ ฉันประหลาดใจมากที่ไม่มีคำตอบใดที่กล่าวถึงโซลูชันที่ง่ายที่สุดเร็วที่สุดและพกพาได้ caseคำสั่ง

case ${variable#[-+]} in
  *[!0-9]* | '') echo Not a number ;;
  * ) echo Valid number ;;
esac

การตัดเครื่องหมายใด ๆ ก่อนการเปรียบเทียบให้ความรู้สึกเหมือนเป็นการแฮ็ก แต่นั่นทำให้นิพจน์สำหรับคำสั่ง case นั้นง่ายขึ้นมาก


4
ฉันหวังว่าฉันจะโหวตให้คะแนนทุกครั้งที่ฉันกลับมาที่คำถามนี้เนื่องจากการถูกหลอก มันบดเกียร์ของฉันซึ่งโซลูชันที่เรียบง่าย แต่สอดคล้องกับ POSIX ถูกฝังไว้ที่ด้านล่าง
Adrian Frühwirth

3
บางทีคุณควรดูแลสายที่ว่างเปล่า:''|*[!0-9]*)
Niklas Peter

2
BTW: นี่คือเอกสารไวยากรณ์นี้: tldp.org/LDP/abs/html/string-manipulation.html
Niklas Peter

ฉันไม่เอาผิดกับ ABS เป็นพิเศษ เห็นได้ชัดว่ามีการบันทึกไว้ในคู่มือ Bash ด้วย อย่างไรก็ตามส่วนที่คุณเชื่อมโยงไม่ได้อธิบายโครงสร้างเฉพาะนี้ แต่เช่นคำตอบของ @ Nortally
tripleee

@tripleee เอกสารที่เชื่อมโยงอธิบายโครงสร้างสำหรับการลบคำนำหน้าสตริงออกจากตัวแปรที่ใช้ในบรรทัดเคส อยู่ที่ด้านล่างของหน้า แต่ไม่มีจุดยึดดังนั้นฉันจึงไม่สามารถเชื่อมโยงโดยตรงได้โปรดดูหัวข้อ "การลบสตริงย่อย"
Niklas Peter

10

ฉันชอบวิธีแก้ปัญหาโดยใช้การ-eqทดสอบเพราะโดยพื้นฐานแล้วมันเป็นซับเดียว

วิธีแก้ปัญหาของฉันเองคือใช้การขยายพารามิเตอร์เพื่อทิ้งตัวเลขทั้งหมดและดูว่ามีอะไรเหลืออยู่หรือไม่ (ฉันยังใช้ 3.0 ไม่เคยใช้[[หรือexprก่อนหน้านี้ แต่ดีใจที่ได้พบกัน)

if [ "${INPUT_STRING//[0-9]}" = "" ]; then
  # yes, natural number
else
  # no, has non-numeral chars
fi

4
สามารถปรับปรุงเพิ่มเติมได้โดยใช้[ -z "${INPUT_STRING//[0-9]}" ]แต่วิธีแก้ปัญหาที่ดีจริงๆ!
ShellFish

แล้วสัญญาณเชิงลบล่ะ?
scottysseus

การ-eqแก้ปัญหามีปัญหาบางอย่าง ดูที่นี่: stackoverflow.com/a/808740/1858225
Kyle Strand

INPUT_STRING ที่ว่างเปล่าถือเป็นตัวเลขดังนั้นจึงล้มเหลวสำหรับกรณีของฉัน
Manwe

9

สำหรับการพกพา 3.1 (เมื่อ-ทุบตีก่อน=~การทดสอบได้รับการแนะนำ), exprการใช้งาน

if expr "$string" : '-\?[0-9]\+$' >/dev/null
then
  echo "String is a valid integer."
else
  echo "String is not a valid integer."
fi

expr STRING : REGEXค้นหา REGEX ที่จุดเริ่มต้นของ STRING โดยสะท้อนกลุ่มแรก (หรือความยาวของการจับคู่หากไม่มี) และส่งคืนความสำเร็จ / ล้มเหลว นี่คือไวยากรณ์ regex \เก่าเพราะฉะนั้นส่วนที่เกิน -\?หมายถึง "อาจ-" [0-9]\+หมายถึง "หนึ่งหลักขึ้นไป" และ$หมายถึง "จุดสิ้นสุดของสตริง"

Bash ยังรองรับ globs แบบขยายแม้ว่าฉันจะจำไม่ได้ว่ารุ่นไหนเป็นต้นไป

shopt -s extglob
case "$string" of
    @(-|)[0-9]*([0-9]))
        echo "String is a valid integer." ;;
    *)
        echo "String is not a valid integer." ;;
esac

# equivalently, [[ $string = @(-|)[0-9]*([0-9])) ]]

@(-|)หมายถึง " -หรือไม่มีอะไร" [0-9]หมายถึง "หลัก" และ*([0-9])หมายถึง "เลขศูนย์ขึ้นไป"


ขอบคุณชั่วคราวมาก ฉันไม่เคยเห็นไวยากรณ์ = ~ มาก่อน - และยังไม่รู้ว่ามันควรจะหมายถึงอะไร - เท่ากันโดยประมาณ?! ... ฉันไม่เคยรู้สึกตื่นเต้นเลยที่จะได้โปรแกรม BASH มาก่อน แต่บางครั้งมันก็จำเป็น!
Richard T

ในawk, ~คือ "การจับคู่ regex" ผู้ประกอบการ ใน Perl (ตามที่คัดลอกมาจาก C) ~ถูกนำมาใช้แล้วสำหรับ "บิตสมบูรณ์" =~ดังนั้นพวกเขาจึงใช้ สัญกรณ์ในภายหลังนี้ได้คัดลอกไปยังภาษาอื่น ๆ (Perl 5.10 และ Perl 6 ชอบ~~มากกว่า แต่นั่นไม่มีผลกระทบที่นี่) ฉันคิดว่าคุณอาจมองว่ามันเป็นความเท่าเทียมกันโดยประมาณ ...
ephemient

โพสต์และแก้ไขได้ดีเยี่ยม! ฉันขอบคุณมากที่อธิบายความหมาย ฉันหวังว่าฉันจะทำเครื่องหมายทั้งของคุณและโพสต์ของอิกนาซิโอเป็นคำตอบที่ถูกต้อง -frown- พวกคุณยอดเยี่ยมทั้งคู่ แต่ในขณะที่คุณมีชื่อเสียงเป็นสองเท่าฉันก็ให้อิกนาซิโอ - หวังว่าคุณจะเข้าใจ! -smile-
Richard T

4

นี่เป็นอีกสิ่งที่ต้องทำ (ใช้คำสั่ง test builtin และรหัสส่งคืนเท่านั้น):

function is_int() { return $(test "$@" -eq "$@" > /dev/null 2>&1); } 

input="-123"

if $(is_int "${input}");
then
   echo "Input: ${input}"
   echo "Integer: $[${input}]"
else
   echo "Not an integer: ${input}"
fi

1
ไม่จำเป็นต้องใช้$()กับif. สิ่งนี้ใช้ได้: if is_int "$input". นอกจากนี้$[]แบบฟอร์มยังเลิกใช้งาน ใช้$(())แทน ภายในทั้งสองอย่างสามารถละเว้นเครื่องหมายดอลลาร์ได้: echo "Integer: $((input))"ไม่จำเป็นต้องใช้เครื่องหมายวงเล็บปีกกาที่ใดก็ได้ในสคริปต์ของคุณ
หยุดชั่วคราวจนกว่าจะมีประกาศอีกครั้ง

ฉันคาดหวังว่าสิ่งนี้จะจัดการกับตัวเลขในสัญกรณ์ฐานของ Bash เป็นจำนวนเต็มที่ถูกต้อง (ซึ่งแน่นอนว่าเป็นจำนวนเต็ม แต่อาจไม่เห็นด้วยกับของคุณ) แต่testดูเหมือนจะไม่รองรับสิ่งนี้ [[ไม่แม้ว่า [[ 16#aa -eq 16#aa ]] && echo integerพิมพ์ "จำนวนเต็ม"
tripleee

โปรดทราบว่า[[ส่งคืนผลบวกเท็จสำหรับวิธีนี้ เช่น[[ f -eq f ]]ประสบความสำเร็จ จึงต้องใช้testหรือ[.
spinup

3

คุณสามารถตัดตัวเลขที่ไม่ใช่ตัวเลขและทำการเปรียบเทียบได้ นี่คือสคริปต์สาธิต:

for num in "44" "-44" "44-" "4-4" "a4" "4a" ".4" "4.4" "-4.4" "09"
do
    match=${num//[^[:digit:]]}    # strip non-digits
    match=${match#0*}             # strip leading zeros
    echo -en "$num\t$match\t"
    case $num in
        $match|-$match)    echo "Integer";;
                     *)    echo "Not integer";;
    esac
done

นี่คือลักษณะของผลลัพธ์การทดสอบ:

44 44 จำนวนเต็ม
-44 44 จำนวนเต็ม
44-44 ไม่ใช่จำนวนเต็ม
4-4 44 ไม่ใช่จำนวนเต็ม
a4 4 ไม่ใช่จำนวนเต็ม
4a 4 ไม่ใช่จำนวนเต็ม
.4 4 ไม่ใช่จำนวนเต็ม
4.4 44 ไม่ใช่จำนวนเต็ม
-4.4 44 ไม่ใช่จำนวนเต็ม
09 9 ไม่ใช่จำนวนเต็ม

สวัสดีเดนนิสขอขอบคุณที่แนะนำฉันเกี่ยวกับไวยากรณ์ทางด้านขวาของการจับคู่ = ด้านบน ฉันไม่เคยสังเกตไวยากรณ์ประเภทนั้นมาก่อน ฉันรู้จักไวยากรณ์บางส่วนจาก tr (ยูทิลิตี้ที่ฉันไม่ค่อยเชี่ยวชาญ แต่บางครั้งก็คลำทางผ่าน) ฉันจะอ่านไวยากรณ์ดังกล่าวได้ที่ไหน (เช่นสิ่งนี้เรียกว่าอะไร) ขอบคุณ
Richard T

คุณสามารถดูในหน้า Bash man ในส่วนที่เรียกว่า "การขยายพารามิเตอร์" เพื่อดูข้อมูลเกี่ยวกับ${var//string}และ${var#string}ในส่วนที่เรียกว่า "การจับคู่รูปแบบ" สำหรับ [^ [: digit:]] `(ซึ่งครอบคลุมด้วยman 7 regex)
หยุดชั่วคราวจนกว่าจะมีประกาศอีกครั้ง

1
match=${match#0*}ไม่ได้ตัดเลขศูนย์นำมันแถบมากที่สุดคนหนึ่งศูนย์ การใช้การขยายสามารถทำได้โดยใช้extglobผ่านmatch=${match##+(0)}.
Adrian Frühwirth

ไม่ใช่ 9 หรือ 09 เป็นจำนวนเต็ม?
Mike Q

@MikeQ: 09ไม่ใช่จำนวนเต็มถ้าคุณพิจารณาว่าจำนวนเต็มไม่มีศูนย์นำหน้า การทดสอบคือว่าอินพุต ( 09) เท่ากับเวอร์ชันที่ผ่านการฆ่าเชื้อแล้วหรือไม่ ( 9- จำนวนเต็ม) และไม่
หยุดชั่วคราวจนกว่าจะมีประกาศอีกครั้ง

2

สำหรับฉันวิธีแก้ปัญหาที่ง่ายที่สุดคือการใช้ตัวแปรภายใน(())นิพจน์ดังนี้:

if ((VAR > 0))
then
  echo "$VAR is a positive integer."
fi

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

เป็นแหลมออกในความคิดเห็นนี้สามารถทำให้คุณอยู่ภายใต้การโจมตีโค้ด: ผู้(( ))ประเมินผู้ประกอบการVARตามที่ระบุไว้ในArithmetic Evaluationส่วนของทุบตี (1) หน้าคน ดังนั้นคุณไม่ควรใช้เทคนิคนี้เมื่อแหล่งที่มาของเนื้อหาVARไม่แน่นอน (และไม่ควรใช้รูปแบบการขยายตัวแปรอื่น ๆ แน่นอน)


คุณสามารถทำได้ง่ายขึ้นด้วยif (( var )); then echo "$var is an int."; fi
Aaron R.

2
แต่นั่นจะคืนค่าจริงสำหรับจำนวนเต็มลบ @aaronr ไม่ใช่สิ่งที่ OP กำลังมองหา
Trebor Rude

2
สิ่งนี้อันตรายโปรดดู: n = 1; var = "n"; ถ้า ((var)); จากนั้น echo "$ var เป็น int"; fi
jarno

2
นี้เป็นความคิดที่ดีมากและอาจมีการดำเนินการโค้ด: VAR='a[$(ls)]'; if ((VAR > 0)); then echo "$VAR is a positive integer"; fiลองเอง: ณ lsจุดนี้คุณกำลังฉันดีใจที่ไม่ได้ป้อนคำสั่งชั่วร้ายบางอย่างแทน เนื่องจาก OP กล่าวถึงอินพุตของผู้ใช้ฉันหวังเป็นอย่างยิ่งว่าคุณจะไม่ใช้สิ่งนี้กับการป้อนข้อมูลของผู้ใช้ในรหัสการผลิต!
gniourf_gniourf

สิ่งนี้จะใช้ไม่ได้หากสตริงมีตัวเลขเช่น:agent007
brablc

1

หรือด้วย sed:

   test -z $(echo "2000" | sed s/[0-9]//g) && echo "integer" || echo "no integer"
   # integer

   test -z $(echo "ab12" | sed s/[0-9]//g) && echo "integer" || echo "no integer"
   # no integer

ใน Bash และกระสุน "Bourne plus" อื่น ๆ คุณสามารถหลีกเลี่ยงการแทนที่คำสั่งและคำสั่งภายนอกได้ด้วยtest -z "${string//[0-9]/}" && echo "integer" || echo "no integer"... แม้ว่าโดยทั่วไปแล้วคำตอบของ Dennis Williamson จะ
ก็ตาม

ขอบคุณ! คำตอบเดียวที่ใช้งานได้จริงที่นี่!
ผู้ใช้

ทางเลือกที่เงียบ:if [[ -n "$(printf "%s" "${2}" | sed s/[0-9]//g)" ]]; then
ผู้ใช้

0

เพิ่มคำตอบจาก Ignacio Vazquez-Abrams สิ่งนี้จะช่วยให้เครื่องหมาย + นำหน้าจำนวนเต็มและจะอนุญาตให้จำนวนศูนย์เป็นจุดทศนิยม ตัวอย่างเช่นจะอนุญาตให้ +45.00000000 ถือเป็นจำนวนเต็ม
อย่างไรก็ตามต้องจัดรูปแบบ $ 1 ให้มีจุดทศนิยม 45 ไม่ถือว่าเป็นจำนวนเต็มในที่นี้ แต่ 45.0 คือ

if [[ $1 =~ ^-?[0-9]+.?[0]+$ ]]; then
    echo "yes, this is an integer"
elif [[ $1 =~ ^\+?[0-9]+.?[0]+$ ]]; then
    echo "yes, this is an integer"
else
    echo "no, this is not an integer"
fi

มีเหตุผลที่คุณใช้นิพจน์ทั่วไปสองนิพจน์ที่แตกต่างกันสำหรับจำนวนบวกและลบแทน^[-+]?[0-9]... ?
tripleee

0

สำหรับการหัวเราะฉันเพิ่งสร้างชุดฟังก์ชันเพื่อทำสิ่งนี้อย่างรวดเร็ว (is_string, is_int, is_float เป็นสตริงอัลฟ่าหรืออื่น ๆ ) แต่มีวิธีที่มีประสิทธิภาพมากกว่า (รหัสน้อยกว่า) ในการทำสิ่งนี้:

#!/bin/bash

function strindex() {
    x="${1%%$2*}"
    if [[ "$x" = "$1" ]] ;then
        true
    else
        if [ "${#x}" -gt 0 ] ;then
            false
        else
            true
        fi
    fi
}

function is_int() {
    if is_empty "${1}" ;then
        false
        return
    fi
    tmp=$(echo "${1}" | sed 's/[^0-9]*//g')
    if [[ $tmp == "${1}" ]] || [[ "-${tmp}" == "${1}" ]] ; then
        #echo "INT (${1}) tmp=$tmp"
        true
    else
        #echo "NOT INT (${1}) tmp=$tmp"
        false
    fi
}

function is_float() {
    if is_empty "${1}" ;then
        false
        return
    fi
    if ! strindex "${1}" "-" ; then
        false
        return
    fi
    tmp=$(echo "${1}" | sed 's/[^a-z. ]*//g')
    if [[ $tmp =~ "." ]] ; then
        #echo "FLOAT  (${1}) tmp=$tmp"
        true
    else
        #echo "NOT FLOAT  (${1}) tmp=$tmp"
        false
    fi
}

function is_strict_string() {
    if is_empty "${1}" ;then
        false
        return
    fi
    if [[ "${1}" =~ ^[A-Za-z]+$ ]]; then
        #echo "STRICT STRING (${1})"
        true
    else
        #echo "NOT STRICT STRING (${1})"
        false
    fi
}

function is_string() {
    if is_empty "${1}" || is_int "${1}" || is_float "${1}" || is_strict_string "${1}" ;then
        false
        return
    fi
    if [ ! -z "${1}" ] ;then
        true
        return
    fi
    false
}
function is_empty() {
    if [ -z "${1// }" ] ;then
        true
    else
        false
    fi
}

ดำเนินการทดสอบบางอย่างที่นี่ฉันกำหนดว่า -44 เป็น int แต่ 44- ไม่ใช่ ฯลฯ .. :

for num in "44" "-44" "44-" "4-4" "a4" "4a" ".4" "4.4" "-4.4" "09" "hello" "h3llo!" "!!" " " "" ; do
    if is_int "$num" ;then
        echo "INT = $num"

    elif is_float "$num" ;then
        echo "FLOAT = $num"

    elif is_string "$num" ; then
        echo "STRING = $num"

    elif is_strict_string "$num" ; then
        echo "STRICT STRING = $num"
    else
        echo "OTHER = $num"
    fi
done

เอาท์พุท:

INT = 44
INT = -44
STRING = 44-
STRING = 4-4
STRING = a4
STRING = 4a
FLOAT = .4
FLOAT = 4.4
FLOAT = -4.4
INT = 09
STRICT STRING = hello
STRING = h3llo!
STRING = !!
OTHER =  
OTHER = 

หมายเหตุ: ชั้นนำ 0 สามารถอนุมานอย่างอื่นได้เมื่อเพิ่มตัวเลขเช่นฐานแปดดังนั้นจะเป็นการดีกว่าถ้าคุณตั้งใจจะให้ '09' เป็น int (ซึ่งฉันกำลังทำอยู่) (เช่นexpr 09 + 0หรือแถบด้วย sed)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.