2015-10-27 85 views
3

編輯:請隨意添加額外的驗證,這將是有用的其他人,使用這個簡單的指令。角度輸入限制指令 - 否定正則表達式

-

我試圖創建一個角指令限制輸入的字符在文本框中。我已經成功地使用了幾個常見用例(alphbetical,字母數字和數字),但使用流行的方法來驗證電子郵件地址,日期和貨幣我無法讓指令工作,因爲我需要它否定正則表達式。至少這是我認爲需要做的。

任何貨幣(可選的千分位數和美分),日期(月/日/年)和電子郵件援助非常感謝。我對正則表達式不感興趣。

這是我目前有: http://jsfiddle.net/corydorning/bs05ys69/

HTML

<div ng-app="example"> 
<h1>Validate Directive</h1> 

<p>The Validate directive allow us to restrict the characters an input can accept.</p> 

<h3><code>alphabetical</code> <span style="color: green">(works)</span></h3> 
<p>Restricts input to alphabetical (A-Z, a-z) characters only.</p> 
<label><input type="text" validate="alphabetical" ng-model="validate.alphabetical"/></label> 

<h3><code>alphanumeric</code> <span style="color: green">(works)</span></h3> 
<p>Restricts input to alphanumeric (A-Z, a-z, 0-9) characters only.</p> 
<label><input type="text" validate="alphanumeric" ng-model="validate.alphanumeric" /></label> 

<h3><code>currency</code> <span style="color: red">(doesn't work)</span></h3> 
<p>Restricts input to US currency characters with comma for thousand separator (optional) and cents (optional).</p> 
<label><input type="text" validate="currency.us" ng-model="validate.currency" /></label> 

<h3><code>date</code> <span style="color: red">(doesn't work)</span></h3> 
<p>Restricts input to the mm/dd/yyyy date format only.</p> 
<label><input type="text" validate="date" ng-model="validate.date" /></label> 

<h3><code>email</code> <span style="color: red">(doesn't work)</span></h3> 
<p>Restricts input to email format only.</p> 
<label><input type="text" validate="email" ng-model="validate.email" /></label> 

<h3><code>numeric</code> <span style="color: green">(works)</span></h3> 
<p>Restricts input to numeric (0-9) characters only.</p> 
<label><input type="text" validate="numeric" ng-model="validate.numeric" /></label> 

的JavaScript

angular.module('example', []) 
    .directive('validate', function() { 
    var validations = { 
     // works 
     alphabetical: /[^a-zA-Z]*$/, 

     // works 
     alphanumeric: /[^a-zA-Z0-9]*$/, 

     // doesn't work - need to negate? 
     // taken from: http://stackoverflow.com/questions/354044/what-is-the-best-u-s-currency-regex 
     currency: /^[+-]?[0-9]{1,3}(?:,?[0-9]{3})*(?:\.[0-9]{2})?$/, 

     // doesn't work - need to negate? 
     // taken from here: http://stackoverflow.com/questions/15196451/regular-expression-to-validate-datetime-format-mm-dd-yyyy 
     date: /(?:0[1-9]|1[0-2])\/(?:0[1-9]|[12][0-9]|3[01])\/(?:19|20)[0-9]{2}/, 

     // doesn't work - need to negate? 
     // taken from: http://stackoverflow.com/questions/46155/validate-email-address-in-javascript 
     email: /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i, 

     // works 
     numeric: /[^0-9]*$/ 
    }; 

    return { 
    require: 'ngModel', 

    scope: { 
     validate: '@' 
    }, 

    link: function (scope, element, attrs, modelCtrl) { 
     var pattern = validations[scope.validate] || scope.validate 
     ; 

     modelCtrl.$parsers.push(function (inputValue) { 
     var transformedInput = inputValue.replace(pattern, '') 
     ; 

     if (transformedInput != inputValue) { 
      modelCtrl.$setViewValue(transformedInput); 
      modelCtrl.$render(); 
     } 

     return transformedInput; 
     }); 
    } 
    }; 
}); 
+0

是否僅僅希望在輸入結尾使用無效字符來糾正輸入(比較在第一個正則表達式中使用$)?我會理解這一點,因爲當在字符串中間鍵入字符時,校正器將插入符號移動到最後是不方便的。另一方面,這不會阻止用戶插入無效字符......只要告訴我您是否期望驗證僅拒絕具有錯誤結尾的字符串。 – trincot

+0

我希望它必須與用戶輸入的格式相匹配。如果與格式不匹配,則無法輸入密鑰 – CoryDorning

+0

那麼您如何期待某人輸入日期?如果你從頭開始打字,那麼當你輸入第一個數字時,你的輸入將被拒絕,因爲它不是一個有效的日期... – trincot

回答

1

我很肯定,有更好的辦法,可能正則表達式也不是最好的工具,但這裏是我的主張。

這樣,你只能限制哪些字符被允許輸入,並強制用戶使用正確的格式,但你還需要驗證最終用戶輸入後,將完成打字,但這是另一回事。

對於輸入和驗證輸入,字母,數字和字母數字非常簡單,因爲它清楚您可以鍵入什麼,以及什麼是正確的最終輸入。但是,對於日期,郵件,貨幣,您無法使用正則表達式驗證輸入是否爲完整的有效輸入,因爲用戶需要先輸入它,同時輸入需要通過最終有效輸入無效。所以,這是一兩件事,比如限制用戶的日期格式鍵入只是數字和/,如:12/12/1988,但最終你需要檢查,如果他輸入正確的日期或例如只是12/12/126。當用戶提供答案或文本字段失去焦點時,需要檢查這一點。

如果只想驗證一個輸入的字符,你可以用這個嘗試:

JSFiddle DEMO

第一個變化:

var transformedInput = inputValue.replace(pattern, '') 

var transformedInput = inputValue.replace(pattern, '$1') 

然後使用正則表達式:

  • /^([a-zA-Z]*(?=[^a-zA-Z]))./ - 字母
  • /^([a-zA-Z0-9]*(?=[^a-zA-Z0-9]))./ - 字母數字
  • /(\.((?=[^\d])|\d{2}(?![^,\d.]))|,((?=[^\d])|\d{3}(?=[^,.$])|(?=\d{1,2}[^\d]))|\$(?=.)|\d{4,}(?=,)).|[^\d,.$]|^\$/ - 貨幣(允許字符串,如:343243.34,1,123,345.34,0.05帶有或不帶有$)
  • ^(((0[1-9]|1[012])|(\d{2}\/\d{2}))(?=[^\/])|((\d)|(\d{2}\/\d{2}\/\d{1,3})|(.+\/))(?=[^\d])|\d{2}\/\d{2}\/\d{4}(?=.)).|^(1[3-9]|[2-9]\d)|((?!^)(3[2-9]|[4-9]\d)\/)|[3-9]\d{3}|2[1-9]\d{2}|(?!^)\/\d\/|^\/|[^\d/] - 日期(00-12/00-31/0000- 2099)
  • /^(\d*(?=[^\d]))./ - 數字
  • /^([\w.$-]+\@[\w.]+(?=[^\w.])|[\w.$-]+\@(?=[^\w.-])|[\[email protected]]+(?=[^\[email protected]])).$|\.(?=[^\[email protected]]).|[^\[email protected]]|^[^\w]|\.([email protected]).|@(?=\.)./i - 電子郵件

一般來說,使用這種模式:

([valid characters or structure] captured in group $1)(?= positive lookahead for not allowed characters) any character 

實際上它會捕獲組$1所有有效的字符,而如果無效字符的用戶類型,整個字符串被替換已拍攝有效字符從組$1。補充部分應排除一些明顯無效的字符,如郵件中的@@或貨幣中的34...2

瞭解這些正則表達式是如何工作的,儘管它看起來相當複雜,但我認爲通過添加額外的允許/不允許的字符可以很容易地擴展它。

驗證貨幣,日期和郵件的正則表達式很容易找到,所以我覺得在這裏發佈它是多餘的。

OffTopic。演示中的currency部分還有什麼不起作用,它是因爲:validate="currency.us"而不是validate="currency",或者至少它在此修改後有效。

+0

這似乎工作得很好。謝謝! – CoryDorning

+0

在貨幣示例中,允許將'$'放在字段的末尾。我怎樣才能刪除它,所以它不被允許或剛開始允許? – CoryDorning

+0

將此正則表達式用於貨幣不允許使用'$'符號: '/(\。((?= [^ \ d])| \ d {2}(?![^,\ d。]))| ,((= [^ \ d])|?\ d {3}(= [^,...])|?(= \ d {1,2} [^ \ d])?)|?\ $(= 。)| \ d {4,}(?=,))。| [^ \ d,。] |^\ $ /' – CoryDorning

1

在我看來,創建正則表達式是不可能的,它可以用於將日期或電子郵件與您使用的解析器 匹配。這主要是因爲您的 正則表達式中有可能需要非捕獲組,而您的解析器函數中沒有用 inputValue.replace(pattern, '')調用所取代。這是在JavaScript中不可能的 部分。 JavaScript取代了您在非捕獲組中也放入的內容。

所以......你需要採取不同的方法。我建議去積極的 正則表達式,這將產生匹配時,輸入有效。 然後,您當然需要更改解析器的代碼。你可以例如 決定刪除輸入文本末尾的字符,直到通過 正則表達式測試。這你可以編碼如下:

modelCtrl.$parsers.push(function (inputValue) { 
    var transformedInput = inputValue; 
    while (transformedInput && !pattern.exec(transformedInput)) { 
     // validation fails: chop off last character and try again 
     transformedInput = transformedInput.slice(0, -1); 
    } 

    if (transformedInput !== inputValue) { 
     modelCtrl.$setViewValue(transformedInput); 
     modelCtrl.$render(); 
    } 

    return transformedInput; 
    }); 

現在的生活變得更容易了。請注意,您會以不會拒絕部分輸入的方式製作常規 表達式。所以「01 /」應該是 認爲有效的日期,否則用戶永遠不能輸入日期。另一方面,在 另一方面,一旦明確添加字符將不再允許有效輸入 ,正則表達式應拒絕它。因此,「101」應該是 作爲日期被拒絕,因爲您不能在最後添加字符以使其成爲有效日期。

此外,所有這些正則表達式都應檢查整個輸入,因此它們需要使用^$符號。

以下是對於(部分)日期的正則表達式可以是這樣的:

^([0-9]{0,2}|[0-9]{2}[\/]([0-9]{0,2}|[0-9]{2}[\/][0-9]{0,4}))$ 

這意味着:爲0〜2位的輸入是有效的,或隨後通過斜線恰好2位數,隨後由任一:

  1. 0至2的數字,或
  2. 正好2位數字加一斜線,然後0至4個數字

不可否認,並不像您找到的那樣聰明,但那需要進行大量的編輯以允許部分輸入日期。這是可能的,但 它代表了一個非常長的表達與很多括號和|

一旦所有的正則表達式設置,你會考慮進一步提高 解析器。一個想法是不讓它從最終砍下字符,但 讓它某處取出一個字符測試所有字符串比較原始, ,看看哪一個通過測試。如果沒有辦法發現刪除一個角色,並有 成功,然後在輸入值中的任何地點刪除兩個連續的字符,然後 三個...等,直到找到通過測試的值或者在到達空值。

這將工作的案件好不到哪用戶插入字符一半他們的意見。 只是一個想法...