2010-07-19 44 views
7

Tôi mới để UNIX, chỉ có bắt đầu nó tại nơi làm việc ngày hôm nay, nhưng có kinh nghiệm với Java, và có đoạn mã sau:Kiểm tra một chuỗi để xem nếu nó chứa ký tự số trong UNIX

#/bin/bash 
echo "Please enter a word:" 
read word 
grep -i $word $1 | cut -d',' -f1,2 | tr "," "-"> output 

tác phẩm này tốt, nhưng những gì tôi bây giờ cần làm là để kiểm tra khi từ được đọc, rằng nó không chứa gì ngoài chữ cái và nếu nó có ký tự số trong in "đầu vào không hợp lệ!" và yêu cầu họ nhập lại. Tôi giả định các biểu thức chính quy với một câu lệnh if sẽ là cách dễ dàng để làm điều này nhưng tôi không thể có được đầu xung quanh cách sử dụng chúng trong UNIX như tôi đã quen với ứng dụng Java của chúng. Bất kỳ trợ giúp với điều này sẽ được đánh giá rất nhiều, vì tôi không thể tìm thấy sự giúp đỡ khi tìm kiếm như tất cả các giải pháp với các biểu thức thông thường trong linux tôi thấy chỉ xử lý nếu nó hoặc là tất cả các số hay không.

Trả lời

17

Tuy nhiên, một cách tiếp cận khác. Grep thoát với 0 nếu kết hợp được tìm thấy, vì vậy bạn có thể kiểm tra mã lối ra:

echo "${word}" | grep -q '[0-9]' 
if [ $? = 0 ]; then 
    echo 'Invalid input' 
fi 

Đây là /bin/sh tương thích.


Kết hợp Daenyth và John đề nghị, điều này trở thành

if echo "${word}" | grep '[0-9]' >/dev/null; then 
    echo 'Invalid input' 
fi 
+3

'-q' để grep không được di chuyển bên ngoài GNU.Nếu bạn muốn tính di động đầy đủ (Lý do duy nhất để sử dụng sh), sử dụng '>/dev/null 2> & 1' – Daenyth

+0

+1, Đây là một giải pháp UNIX, đơn giản và sạch sẽ. – Anders

+0

@ Bạn chắc chắn bạn hoàn toàn đúng, và tôi thậm chí đã làm điều đó khi tôi thử nó trên hệ thống của tôi, sau đó thêm '-q' khi tôi đăng câu trả lời của mình. Dường như tôi đã chỉ là GNU quá lâu. –

0

Một xách tay (giả sử bash> = 3) cách để làm điều này là để loại bỏ tất cả các số và thử nghiệm cho chiều dài:

#!/bin/bash 
read -p "Enter a number" var 
if [[ -n ${var//[0-9]} ]]; then 
    echo "Contains non-numbers!" 
else 
    echo "ok!" 
fi 

Đến từ Java, điều quan trọng cần lưu ý bash mà không có khái niệm thực sự của đối tượng hoặc kiểu dữ liệu. Tất cả mọi thứ là một chuỗi, và cấu trúc dữ liệu phức tạp là đau đớn nhất.

Để biết thêm thông tin về những gì tôi đã làm và các chức năng liên quan khác, google để xử lý chuỗi bash.

+1

Giả sử mèo bash? Thật tàn nhẫn. – MikeD

7

Nhà điều hành khung đôi là một phiên bản mở rộng của lệnh test mà hỗ trợ regexes qua các nhà điều hành =~:

#!/bin/bash 

while true; do 
    read -p "Please enter a word: " word 
    if [[ $word =~ [0-9] ]]; then 
     echo 'Invalid input!' >&2 
    else 
     break 
    fi 
done 

Đây là một tính năng bash cụ thể. Bash là một trình bao mới hơn không có sẵn trên tất cả các tính năng của UNIX - mặc dù là "mới hơn", tôi có nghĩa là "chỉ mới phát triển trong thời đại ống chân không" và "không phải tất cả các hương vị của UNIX" của Solaris và HP-UX. Theo quan điểm của tôi, đây là tùy chọn đơn giản nhất và bash rất nhiều di động trong những ngày này, nhưng nếu di chuyển đến UNIX cũ thì thực tế quan trọng thì bạn sẽ cần sử dụng các câu trả lời tương thích với các áp phích khác. sh là vỏ phổ biến nhất và được hỗ trợ rộng rãi nhất, nhưng giá bạn trả cho tính di động sẽ mất đi những thứ như =~.

3

Nếu bạn đang cố viết mã shell di động, các tùy chọn thao tác chuỗi của bạn bị giới hạn. Bạn có thể sử dụng các mẫu vỏ globbing (mà là ít hơn rất nhiều biểu cảm hơn regexps) trong case xây dựng:

export LC_COLLATE=C 
read word 
while 
    case "$word" in 
    *[!A-Za-z]*) echo >&2 "Invalid input, please enter letters only"; true;; 
    *) false;; 
    esac 
do 
    read word 
done 

EDIT: thiết LC_COLLATE là cần thiết vì trong hầu hết các phi C miền địa phương, nhân vật dao động như A-Z don' t có ý nghĩa "rõ ràng". Tôi cho rằng bạn chỉ muốn có chữ cái ASCII; nếu bạn cũng muốn các chữ cái có dấu phụ, không thay đổi LC_COLLATE và thay thế A-Za-z bằng [:alpha:] (do đó toàn bộ mẫu sẽ trở thành *[![:alpha:]]*).

Để xem regex đầy đủ, hãy xem lệnh expr. EDIT: Lưu ý rằng expr, giống như một số công cụ vỏ cơ bản khác, có các cạm bẫy với một số chuỗi đặc biệt; các ký tự z dưới đây ngăn không cho $word được hiểu là từ dành riêng bởi expr.

export LC_COLLATE=C 
read word 
while expr "z$word" : 'z[A-Za-z]*$' >/dev/null; then 
    echo >&2 "Invalid input, please enter letters only" 
    read word 
fi 

Nếu bạn chỉ nhắm mục tiêu các phiên bản gần đây đủ của bash, có những lựa chọn khác, chẳng hạn như các nhà điều hành của =~[[ ... ]] lệnh có điều kiện.

Lưu ý rằng dòng cuối cùng của bạn có một lỗi, lệnh đầu tiên nên

grep -i "$word" "$1" 

Các dấu ngoặc kép là vì phần nào phản trực giác, "$foo" có nghĩa là “giá trị của biến được gọi là foo” trong khi đồng bằng $foo có nghĩa là “ lấy giá trị của foo, chia thành các từ riêng biệt trong đó nó chứa khoảng trắng và xử lý từng từ như là một mẫu hình cầu và cố gắng mở rộng nó ”. (Thực tế nếu bạn đã kiểm tra rằng $word chỉ chứa các chữ cái, để lại dấu ngoặc kép sẽ không gây hại gì, nhưng phải mất nhiều thời gian hơn để nghĩ về những trường hợp đặc biệt này hơn là chỉ đặt dấu ngoặc kép mỗi lần.)

+0

Trường hợp bạn đã liệt kê không thành công đối với đầu vào không phải số ascii. – Daenyth

+0

@Điểm: đúng, tất cả các giải pháp sử dụng 'A-Za-z' giả định một miền địa phương ASCII. Vì vậy, hãy để tôi thêm chú thích: nếu bạn muốn cho phép tất cả các chữ cái trong ngôn ngữ của bạn (bao gồm cả các chữ cái có dấu phụ), thay thế 'A-Za-z' bằng '[: alpha:]' ở mọi nơi ('case',' expr' , 'grep', ...) (có, bạn sẽ có dấu ngoặc trong dấu ngoặc vuông). Nếu bạn chỉ muốn các chữ cái ASCII, hãy đặt 'xuất LC_COLLATE = C' gần đầu tập lệnh của bạn. – Gilles

+0

Giải pháp đơn giản chỉ là đảo ngược nó - kiểm tra rằng nó chứa '[^ 0-9]'. Danh sách trắng dễ hơn danh sách đen. – Daenyth

0

Chơi xung quanh với việc mở rộng tham số và nhân vật lớp Bash:

# cf. http://wiki.bash-hackers.org/syntax/pe 

word="abc1def" 
word="abc,def" 
word=$'abc\177def' 
# cf. http://mywiki.wooledge.org/BashFAQ/058 (no NUL byte in Bash variable) 
word=$'abc\000def' 
word="abcdef" 

(
set -xv 
[[ "${word}" != "${word/[[:digit:]]/}" ]] && echo invalid || echo valid 
[[ -n "${word//[[:alpha:]]/}" ]] && echo invalid || echo valid 
) 
1

Tuy nhiên, một (khá) cách cầm tay để làm điều đó. ..

if test "$word" != "`printf "%s" "$word" | tr -dc '[[:alpha:]]'`"; then 
    echo invalid 
fi 
0

Câu trả lời của mọi người dường như dựa trên thực tế là các ký tự không hợp lệ duy nhất là số. Các câu hỏi ban đầu nói rằng họ cần phải kiểm tra xem chuỗi có chứa "không có gì ngoài chữ cái" hay không.

Tôi nghĩ rằng cách tốt nhất để làm điều đó là

nonalpha=$(echo "$word" | sed 's/[[:alpha:]]//g') 
if [[ ${#nonalpha} -gt 0 ]]; then 
    echo "Invalid character(s): $nonalpha" 
fi 

Nếu bạn tìm thấy trang này tìm kiếm một cách để phát hiện các ký tự số trong chuỗi của bạn thay thế [[(như tôi đã làm!): Alpha: ]] với [[: chữ số:]].

Các vấn đề liên quan