คำตอบที่ให้ไว้ก่อนหน้านี้ทั้งหมดใช้เทคนิคเดียวกัน (ถูกต้อง) เพื่อใช้การค้นหาที่แยกจากกันสำหรับแต่ละข้อกำหนด แต่มีข้อบกพร่องสองสามข้อและข้อบกพร่องที่อาจเกิดขึ้นได้มากขึ้นอยู่กับส่วนหลังที่จะใช้รหัสผ่านจริงๆ
ฉันจะเริ่มต้นด้วย regex จากคำตอบที่ยอมรับ:
^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
ก่อนอื่นเนื่องจาก Java รองรับ\A
และ\z
ฉันชอบใช้สิ่งเหล่านี้เพื่อให้แน่ใจว่าสตริงทั้งหมดได้รับการตรวจสอบความถูกต้องโดยไม่ขึ้นอยู่กับPattern.MULTILINE
. สิ่งนี้ไม่มีผลต่อประสิทธิภาพ แต่หลีกเลี่ยงข้อผิดพลาดเมื่อ regexes ถูกรีไซเคิล
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}\z
ตรวจสอบว่ารหัสผ่านไม่มีช่องว่างและการตรวจสอบความยาวขั้นต่ำสามารถทำได้ในครั้งเดียวโดยใช้ทั้งหมดพร้อมกันโดยการใส่ตัวระบุตัวแปร{8,}
บนชวเลข\S
ที่ จำกัด อักขระที่อนุญาต:
\A(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])\S{8,}\z
หากรหัสผ่านที่ระบุมีช่องว่างการตรวจสอบทั้งหมดจะดำเนินการเพื่อให้การตรวจสอบขั้นสุดท้ายล้มเหลวในช่องว่าง สิ่งนี้สามารถหลีกเลี่ยงได้โดยการแทนที่จุดทั้งหมดด้วย\S
:
\A(?=\S*[0-9])(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[@#$%^&+=])\S{8,}\z
ควรใช้จุดเมื่อคุณต้องการอนุญาตอักขระใด ๆ จริงๆ มิฉะนั้นให้ใช้คลาสอักขระ (ลบ) เพื่อ จำกัด regex ของคุณให้เหลือเฉพาะอักขระที่ได้รับอนุญาตจริงๆ แม้ว่าจะสร้างความแตกต่างเพียงเล็กน้อยในกรณีนี้ แต่การไม่ใช้จุดเมื่อสิ่งอื่นเหมาะสมกว่าเป็นนิสัยที่ดีมาก ฉันเห็นหลายกรณีของการย้อนรอยภัยพิบัติเนื่องจากผู้พัฒนาขี้เกียจเกินไปที่จะใช้สิ่งที่เหมาะสมกว่าจุด
เนื่องจากมีโอกาสดีที่การทดสอบครั้งแรกจะพบอักขระที่เหมาะสมในครึ่งแรกของรหัสผ่านตัวระบุค่าขี้เกียจจึงมีประสิทธิภาพมากขึ้น:
\A(?=\S*?[0-9])(?=\S*?[a-z])(?=\S*?[A-Z])(?=\S*?[@#$%^&+=])\S{8,}\z
แต่ตอนนี้สำหรับปัญหาที่สำคัญจริงๆ: ไม่มีคำตอบใดที่กล่าวถึงความจริงที่ว่าคำถามดั้งเดิมดูเหมือนจะเขียนโดยคนที่คิดใน ASCII แต่ในสตริง Java คือ Unicode อนุญาตให้ใช้อักขระที่ไม่ใช่ ASCII ในรหัสผ่านหรือไม่? หากเป็นเช่นนั้นจะไม่อนุญาตให้ใช้เฉพาะช่องว่าง ASCII หรือควรยกเว้นช่องว่าง Unicode ทั้งหมด
โดยค่าเริ่มต้นจะ\s
จับคู่เฉพาะช่องว่าง ASCII ดังนั้นการผกผันจะ\S
จับคู่อักขระ Unicode ทั้งหมด (เว้นวรรคหรือไม่) และอักขระ ASCII ที่ไม่ใช่ช่องว่างทั้งหมด หากอนุญาตให้ใช้อักขระ Unicode แต่ไม่ใช้ช่องว่าง Unicode UNICODE_CHARACTER_CLASS
แฟล็กสามารถระบุได้เพื่อให้\S
เว้นช่องว่าง Unicode หากไม่อนุญาตให้ใช้อักขระ Unicode [\x21-\x7E]
คุณสามารถใช้แทน\S
เพื่อจับคู่อักขระ ASCII ทั้งหมดที่ไม่ใช่ช่องว่างหรืออักขระควบคุม
ซึ่งนำเราไปสู่ปัญหาที่อาจเกิดขึ้นต่อไป: เราต้องการอนุญาตให้ใช้อักขระควบคุมหรือไม่? ขั้นตอนแรกในการเขียน regex ที่ถูกต้องคือการระบุสิ่งที่คุณต้องการจับคู่และสิ่งที่คุณไม่ต้องการ คำตอบที่ถูกต้องทางเทคนิค 100% เท่านั้นคือข้อกำหนดรหัสผ่านในคำถามไม่ชัดเจนเนื่องจากไม่ได้ระบุว่าอนุญาตให้ใช้ช่วงของอักขระบางช่วงเช่นอักขระควบคุมหรืออักขระที่ไม่ใช่ ASCII หรือไม่