String.indexOf () ของ JavaScript มีเวอร์ชันที่อนุญาตให้มีการแสดงออกปกติหรือไม่


214

ใน javascript มีค่าเทียบเท่ากับ String.indexOf () ที่ใช้นิพจน์ปกติแทนสตริงสำหรับพารามิเตอร์แรกตัวแรกในขณะที่ยังอนุญาตพารามิเตอร์ที่สองอยู่หรือไม่

ฉันต้องทำอะไรซักอย่าง

str.indexOf(/[abc]/ , i);

และ

str.lastIndexOf(/[abc]/ , i);

ในขณะที่ String.search () รับ regexp เป็นพารามิเตอร์มันไม่อนุญาตให้ฉันระบุอาร์กิวเมนต์ที่สอง!

แก้ไข:
สิ่งนี้กลายเป็นหนักกว่าที่ฉันคิดไว้ในตอนแรกดังนั้นฉันจึงเขียนฟังก์ชันทดสอบขนาดเล็กเพื่อทดสอบวิธีแก้ปัญหาที่ให้ไว้ทั้งหมด ... มันจะถือว่า regexIndexOf และ regexLastIndexOf ถูกเพิ่มลงในวัตถุ String

function test (str) {
    var i = str.length +2;
    while (i--) {
        if (str.indexOf('a',i) != str.regexIndexOf(/a/,i)) 
            alert (['failed regexIndexOf ' , str,i , str.indexOf('a',i) , str.regexIndexOf(/a/,i)]) ;
        if (str.lastIndexOf('a',i) != str.regexLastIndexOf(/a/,i) ) 
            alert (['failed regexLastIndexOf ' , str,i,str.lastIndexOf('a',i) , str.regexLastIndexOf(/a/,i)]) ;
    }
}

และฉันกำลังทดสอบดังต่อไปนี้เพื่อให้แน่ใจว่าอย่างน้อยสำหรับอักขระหนึ่งตัว regexp ผลลัพธ์จะเหมือนกับว่าเราใช้ indexOf

// มองหาการทดสอบ a ท่ามกลาง xes
('xxx');
การทดสอบ ( 'AXX');
การทดสอบ ( 'XAX');
การทดสอบ ( 'xxa');
การทดสอบ ( 'แอกซ่า');
การทดสอบ ( 'XAA');
การทดสอบ ( 'AAX');
การทดสอบ ( 'AAA');


|ภายในตรงกับตัวอักษรตัวอักษร[ ] คุณอาจหมายถึง| [abc]
Markus Jarderot

ใช่ขอบคุณคุณขวาฉันจะแก้ไขได้ แต่ regexp ตัวเองเป็นที่ไม่เกี่ยวข้อง ...
แพ็ต

อัปเดตคำตอบของฉัน Pat ขอบคุณสำหรับความคิดเห็นใด ๆ
เจสันตอม่อ

ฉันพบวิธีที่ง่ายและมีประสิทธิภาพคือการใช้ string.match (/ [AZ] /) หากมีไม่มากวิธีการคืนค่าเป็นโมฆะมิฉะนั้นคุณจะได้รับวัตถุคุณสามารถจับคู่ (/ [AZ] /) ดัชนีเพื่อรับดัชนีตัวอักษรตัวแรก
Syler

คำตอบ:


129

เมื่อรวมวิธีการต่าง ๆ ที่กล่าวถึงไปแล้ว (indexOf ค่อนข้างง่าย) ฉันคิดว่านี่เป็นฟังก์ชั่นที่จะใช้เคล็ดลับ:

String.prototype.regexIndexOf = function(regex, startpos) {
    var indexOf = this.substring(startpos || 0).search(regex);
    return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf;
}

String.prototype.regexLastIndexOf = function(regex, startpos) {
    regex = (regex.global) ? regex : new RegExp(regex.source, "g" + (regex.ignoreCase ? "i" : "") + (regex.multiLine ? "m" : ""));
    if(typeof (startpos) == "undefined") {
        startpos = this.length;
    } else if(startpos < 0) {
        startpos = 0;
    }
    var stringToWorkWith = this.substring(0, startpos + 1);
    var lastIndexOf = -1;
    var nextStop = 0;
    while((result = regex.exec(stringToWorkWith)) != null) {
        lastIndexOf = result.index;
        regex.lastIndex = ++nextStop;
    }
    return lastIndexOf;
}

เห็นได้ชัดว่าการปรับเปลี่ยนวัตถุ String ในตัวจะส่งค่าสถานะสีแดงสำหรับคนส่วนใหญ่ แต่นี่อาจเป็นครั้งเดียวที่ไม่ใช่ข้อตกลงที่ยิ่งใหญ่ เพียงแค่ตระหนักถึงมัน


อัปเดต: แก้ไขregexLastIndexOf()เพื่อให้ดูเหมือนว่าจะเลียนแบบในlastIndexOf()ขณะนี้ โปรดแจ้งให้เราทราบหากยังคงล้มเหลวและอยู่ในสถานการณ์ใด


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


คุณregexLastIndexOfจะส่งคืนดัชนีของการแข่งขันที่ไม่ทับซ้อนกันครั้งสุดท้ายเท่านั้น
Markus Jarderot

ขออภัยไม่ใช่ผู้ชาย regex ขนาดใหญ่ - คุณสามารถยกตัวอย่างที่ทำให้ฉันล้มเหลวได้ไหม ฉันขอขอบคุณที่สามารถเรียนรู้เพิ่มเติมได้ แต่คำตอบของคุณไม่ได้ช่วยคนที่ไม่รู้เหมือนฉัน :)
Jason Bunting

Jason ฉันเพิ่งเพิ่มฟังก์ชั่นบางอย่างเพื่อทดสอบในคำถาม นี่คือความล้มเหลว (ในการทดสอบอื่น ๆ ) ต่อไปนี้ 'axx'.lastIndexOf (' a ', 2)! =' axx'.regexLastIndexOf (/ a /, 2)
Pat

2
ฉันคิดว่ามันมีประสิทธิภาพมากขึ้นเพื่อใช้แทนregex.lastIndex = result.index + 1; regex.lastIndex = ++nextStop;มันจะดำเนินการในนัดต่อไปที่เร็วขึ้นหวังอย่างยิ่งโดยไม่ทำให้ผลลัพธ์หายไป
Gedrox

1
หากคุณต้องการดึงมาจาก npm ตอนนี้ฟังก์ชั่น util ทั้งสองนี้จะใช้กับ NPM เป็น: npmjs.com/package/index-of-regex
Capaj

185

อินสแตนซ์ของตัวStringสร้างมี.search()วิธีการที่ยอมรับ RegExp และส่งกลับค่าดัชนีของการแข่งขันครั้งแรก

ในการเริ่มการค้นหาจากตำแหน่งเฉพาะ (แกล้งทำพารามิเตอร์ที่สองของ.indexOf()) คุณสามารถsliceปิดiอักขระแรก:

str.slice(i).search(/re/)

แต่นี้จะได้รับดัชนีในสตริงสั้น (หลังจากส่วนแรกถูกหั่นออก) เพื่อให้คุณจะต้องการแล้วเพิ่มความยาวของส่วนที่ตัดออก (คนi) -1เพื่อจัดทำดัชนีกลับมาถ้ามันไม่ได้ สิ่งนี้จะให้ดัชนีในสตริงเดิม:

function regexIndexOf(text, re, i) {
    var indexInSuffix = text.slice(i).search(re);
    return indexInSuffix < 0 ? indexInSuffix : indexInSuffix + i;
}

1
จากคำถาม: ในขณะที่ String.search () ใช้ regexp เป็นพารามิเตอร์มันไม่อนุญาตให้ฉันระบุอาร์กิวเมนต์ที่สอง!
Pat

14
str.substr (i) .search (/ re /)
Glenn

6
ทางออกที่ดี แต่ผลลัพธ์แตกต่างกันเล็กน้อย indexOf จะส่งคืนตัวเลขจากจุดเริ่มต้น (โดยไม่คำนึงถึงออฟเซ็ต) ในขณะที่สิ่งนี้จะส่งคืนตำแหน่งจากออฟเซ็ต ดังนั้นสำหรับความเท่าเทียมกันคุณจะต้องการอะไรเช่นนี้อีกมากมาย:function regexIndexOf(text, offset) { var initial = text.substr(offset).search(/re/); if(initial >= 0) { initial += offset; } return initial; }
gkoberger

39

ฉันมีเวอร์ชั่นสั้นสำหรับคุณ มันใช้งานได้ดีสำหรับฉัน!

var match      = str.match(/[abc]/gi);
var firstIndex = str.indexOf(match[0]);
var lastIndex  = str.lastIndexOf(match[match.length-1]);

และถ้าคุณต้องการรุ่นต้นแบบ:

String.prototype.indexOfRegex = function(regex){
  var match = this.match(regex);
  return match ? this.indexOf(match[0]) : -1;
}

String.prototype.lastIndexOfRegex = function(regex){
  var match = this.match(regex);
  return match ? this.lastIndexOf(match[match.length-1]) : -1;
}

แก้ไข : ถ้าคุณต้องการเพิ่มการสนับสนุนจาก fromIndex

String.prototype.indexOfRegex = function(regex, fromIndex){
  var str = fromIndex ? this.substring(fromIndex) : this;
  var match = str.match(regex);
  return match ? str.indexOf(match[0]) + fromIndex : -1;
}

String.prototype.lastIndexOfRegex = function(regex, fromIndex){
  var str = fromIndex ? this.substring(0, fromIndex) : this;
  var match = str.match(regex);
  return match ? str.lastIndexOf(match[match.length-1]) : -1;
}

วิธีใช้ง่าย ๆ อย่างนี้:

var firstIndex = str.indexOfRegex(/[abc]/gi);
var lastIndex  = str.lastIndexOfRegex(/[abc]/gi);

นี่เป็นเคล็ดลับที่ดีจริงๆ จะดีมากถ้าคุณขยายstartIndexพารามิเตอร์เพื่อรับพารามิเตอร์ตามปกติindeoxOfและlastIndexOfทำเช่นนั้น
Robert Koritnik

@RobertKoritnik - ฉันแก้ไขคำตอบของฉันเพื่อสนับสนุนstartIndex(หรือfromIndex) หวังว่ามันจะช่วย!
pmrotule

lastIndexOfRegexควรเพิ่มกลับค่าของfromIndexผลลัพธ์
ปีเตอร์

อัลกอริทึมของคุณจะแตกออกในสถานการณ์ต่อไปนี้: "aRomeo Romeo".indexOfRegex(new RegExp("\\bromeo", 'gi'));ผลลัพธ์จะเป็น 1 เมื่อควรเป็น 7 เนื่องจาก indexOf จะค้นหาเป็นครั้งแรกที่ "romeo" ปรากฏขึ้นไม่ว่าจะเป็นตอนเริ่มต้นของคำหรือไม่
KorelK

13

ใช้:

str.search(regex)

ดูเอกสารประกอบที่นี่


11
@OZZIE: ไม่ไม่ได้จริงๆ โดยทั่วไปแล้วคำตอบของ Glenn (มีประมาณ 150 upvotes) ยกเว้นว่าจะไม่มีคำอธิบายใด ๆไม่สนับสนุนตำแหน่งเริ่มต้นนอกเหนือจาก0นั้นและถูกโพสต์ ... เจ็ดปีต่อมา
ccjmne

7

ตามคำตอบของ BaileyP ความแตกต่างที่สำคัญคือวิธีการเหล่านี้ส่งคืน-1ถ้าไม่สามารถจับคู่รูปแบบได้

แก้ไข:ขอบคุณคำตอบของ Jason Bunting ฉันมีความคิด ทำไมไม่แก้ไข.lastIndexคุณสมบัติของ regex? แม้ว่าสิ่งนี้จะใช้ได้เฉพาะกับลวดลายที่มีค่าสถานะโกลบอล ( /g)

แก้ไข:อัปเดตเพื่อส่งกรณีทดสอบ

String.prototype.regexIndexOf = function(re, startPos) {
    startPos = startPos || 0;

    if (!re.global) {
        var flags = "g" + (re.multiline?"m":"") + (re.ignoreCase?"i":"");
        re = new RegExp(re.source, flags);
    }

    re.lastIndex = startPos;
    var match = re.exec(this);

    if (match) return match.index;
    else return -1;
}

String.prototype.regexLastIndexOf = function(re, startPos) {
    startPos = startPos === undefined ? this.length : startPos;

    if (!re.global) {
        var flags = "g" + (re.multiline?"m":"") + (re.ignoreCase?"i":"");
        re = new RegExp(re.source, flags);
    }

    var lastSuccess = -1;
    for (var pos = 0; pos <= startPos; pos++) {
        re.lastIndex = pos;

        var match = re.exec(this);
        if (!match) break;

        pos = match.index;
        if (pos <= startPos) lastSuccess = pos;
    }

    return lastSuccess;
}

นี่ดูเหมือนจะเป็นสิ่งที่มีแนวโน้มมากที่สุด (หลังจากผ่านการแก้ไขทางไวยากรณ์ไม่กี่ครั้ง) :-) การทดสอบสองสามครั้งล้มเหลวในเงื่อนไขของขอบ สิ่งที่ชอบ 'axx'.lastIndexOf (' a ', 0)! =' axx'.regexLastIndexOf (/ a /, 0) ... ฉันกำลังมองหามันเพื่อดูว่าฉันสามารถแก้ไขกรณีเหล่านี้ได้ไหม
Pat

6

คุณสามารถใช้ substr

str.substr(i).match(/[abc]/);

จากหนังสือ JavaScript ที่เป็นที่รู้จักเผยแพร่โดย O'Reilly: "substr ไม่ได้มาตรฐานโดย ECMAScript และเลิกใช้แล้ว" แต่ฉันชอบแนวคิดพื้นฐานที่อยู่เบื้องหลังสิ่งที่คุณได้รับ
Jason Bunting

1
นั่นไม่ใช่ปัญหา หากคุณกังวลจริงๆเกี่ยวกับมันให้ใช้ String.substring () แทน - คุณเพียงแค่ต้องทำคณิตศาสตร์แตกต่างกันเล็กน้อย นอกจากนี้ JavaScript ไม่ควรยึดติด 100% กับภาษาหลัก
Peter Bailey

ไม่ใช่เรื่องที่ไม่ใช่ปัญหาหากคุณทำให้โค้ดของคุณทำงานกับการใช้งานที่ไม่ได้ใช้ substr เพราะพวกเขาต้องการที่จะปฏิบัติตามมาตรฐาน ECMAScript คุณจะมีปัญหา ได้รับการแทนที่ด้วย substring นั้นไม่ใช่เรื่องยากที่จะทำ แต่มันเป็นเรื่องดีที่จะรู้ทันเหตุการณ์นี้
35490 Jason

1
ช่วงเวลาที่คุณมีปัญหาคุณมีทางออกที่ง่ายมาก ฉันคิดว่าความคิดเห็นนั้นสมเหตุสมผล แต่การโหวตลงมานั้นช่างพูดหยาบคาย
VoronoiPotato

คุณกรุณาแก้ไขคำตอบของคุณเพื่อให้รหัสการสาธิตทำงานได้หรือไม่
vsync

5

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

function reIndexOf(reIn, str, startIndex) {
    var re = new RegExp(reIn.source, 'g' + (reIn.ignoreCase ? 'i' : '') + (reIn.multiLine ? 'm' : ''));
    re.lastIndex = startIndex || 0;
    var res = re.exec(str);
    if(!res) return -1;
    return re.lastIndex - res[0].length;
};

function reLastIndexOf(reIn, str, startIndex) {
    var src = /\$$/.test(reIn.source) && !/\\\$$/.test(reIn.source) ? reIn.source : reIn.source + '(?![\\S\\s]*' + reIn.source + ')';
    var re = new RegExp(src, 'g' + (reIn.ignoreCase ? 'i' : '') + (reIn.multiLine ? 'm' : ''));
    re.lastIndex = startIndex || 0;
    var res = re.exec(str);
    if(!res) return -1;
    return re.lastIndex - res[0].length;
};

reIndexOf(/[abc]/, "tommy can eat");  // Returns 6
reIndexOf(/[abc]/, "tommy can eat", 8);  // Returns 11
reLastIndexOf(/[abc]/, "tommy can eat"); // Returns 11

คุณสามารถสร้างต้นแบบฟังก์ชั่นลงบนวัตถุ RegExp:

RegExp.prototype.indexOf = function(str, startIndex) {
    var re = new RegExp(this.source, 'g' + (this.ignoreCase ? 'i' : '') + (this.multiLine ? 'm' : ''));
    re.lastIndex = startIndex || 0;
    var res = re.exec(str);
    if(!res) return -1;
    return re.lastIndex - res[0].length;
};

RegExp.prototype.lastIndexOf = function(str, startIndex) {
    var src = /\$$/.test(this.source) && !/\\\$$/.test(this.source) ? this.source : this.source + '(?![\\S\\s]*' + this.source + ')';
    var re = new RegExp(src, 'g' + (this.ignoreCase ? 'i' : '') + (this.multiLine ? 'm' : ''));
    re.lastIndex = startIndex || 0;
    var res = re.exec(str);
    if(!res) return -1;
    return re.lastIndex - res[0].length;
};


/[abc]/.indexOf("tommy can eat");  // Returns 6
/[abc]/.indexOf("tommy can eat", 8);  // Returns 11
/[abc]/.lastIndexOf("tommy can eat"); // Returns 11

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


4

มันไม่ได้เป็นไปตามปกติ แต่คุณสามารถเพิ่มฟังก์ชันนี้ได้อย่างแน่นอน

<script type="text/javascript">

String.prototype.regexIndexOf = function( pattern, startIndex )
{
    startIndex = startIndex || 0;
    var searchResult = this.substr( startIndex ).search( pattern );
    return ( -1 === searchResult ) ? -1 : searchResult + startIndex;
}

String.prototype.regexLastIndexOf = function( pattern, startIndex )
{
    startIndex = startIndex === undefined ? this.length : startIndex;
    var searchResult = this.substr( 0, startIndex ).reverse().regexIndexOf( pattern, 0 );
    return ( -1 === searchResult ) ? -1 : this.length - ++searchResult;
}

String.prototype.reverse = function()
{
    return this.split('').reverse().join('');
}

// Indexes 0123456789
var str = 'caabbccdda';

alert( [
        str.regexIndexOf( /[cd]/, 4 )
    ,   str.regexLastIndexOf( /[cd]/, 4 )
    ,   str.regexIndexOf( /[yz]/, 4 )
    ,   str.regexLastIndexOf( /[yz]/, 4 )
    ,   str.lastIndexOf( 'd', 4 )
    ,   str.regexLastIndexOf( /d/, 4 )
    ,   str.lastIndexOf( 'd' )
    ,   str.regexLastIndexOf( /d/ )
    ]
);

</script>

ฉันไม่ได้ทดสอบวิธีการเหล่านี้อย่างเต็มที่ แต่ดูเหมือนว่าพวกเขาจะทำงานได้ดี


อัปเดตเพื่อจัดการกับกรณีเหล่านี้
Peter Bailey

ทุกครั้งที่ฉันจะยอมรับคำตอบนี้ฉันจะพบเคสใหม่! สิ่งเหล่านี้ให้ผลลัพธ์ที่แตกต่าง! การแจ้งเตือน ([str.lastIndexOf (/ [d] /, 4), str.regexLastIndexOf (/ [d] /, 4)]);
Pat

แน่นอนว่าพวกเขาคือ - str.lastIndexOf จะทำการข่มขู่ประเภทในรูปแบบ - แปลงมันเป็นสตริง ไม่พบสตริง "/ [d] /" ในอินพุตดังนั้นการส่งคืน -1 จึงแม่นยำ
Peter Bailey

เข้าใจแล้ว หลังจากอ่านข้อมูลจำเพาะเกี่ยวกับ String.lastIndexOf () - ฉันแค่เข้าใจผิดว่าอาร์กิวเมนต์นั้นทำงานอย่างไร เวอร์ชั่นใหม่นี้ควรรองรับ
Peter Bailey

มีบางอย่างไม่ถูกต้อง แต่มันกำลังจะสาย ... ฉันจะลองทำกรณีทดสอบและอาจจะแก้ไขในตอนเช้า ขออภัยสำหรับปัญหาจนถึงขณะนี้
Pat

2

หลังจากการแก้ปัญหาที่เสนอทั้งหมดล้มเหลวในการทดสอบของฉันไม่ทางใดก็ทางหนึ่ง (แก้ไข: บางส่วนได้รับการปรับปรุงให้ผ่านการทดสอบหลังจากที่ฉันเขียน) ฉันพบว่าการใช้ mozilla สำหรับArray.indexOfและArray.lastIndexOf

ฉันใช้สิ่งเหล่านี้เพื่อสร้างเวอร์ชันของ String.prototype.regexIndexOf และ String.prototype.regexLastIndexOf เวอร์ชันดังต่อไปนี้:

String.prototype.regexIndexOf = function(elt /*, from*/)
  {
    var arr = this.split('');
    var len = arr.length;

    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from) : Math.floor(from);
    if (from < 0)
      from += len;

    for (; from < len; from++) {
      if (from in arr && elt.exec(arr[from]) ) 
        return from;
    }
    return -1;
};

String.prototype.regexLastIndexOf = function(elt /*, from*/)
  {
    var arr = this.split('');
    var len = arr.length;

    var from = Number(arguments[1]);
    if (isNaN(from)) {
      from = len - 1;
    } else {
      from = (from < 0) ? Math.ceil(from) : Math.floor(from);
      if (from < 0)
        from += len;
      else if (from >= len)
        from = len - 1;
    }

    for (; from > -1; from--) {
      if (from in arr && elt.exec(arr[from]) )
        return from;
    }
    return -1;
  };

ดูเหมือนว่าพวกเขาจะผ่านฟังก์ชั่นทดสอบที่ฉันให้ไว้ในคำถาม

เห็นได้ชัดว่าพวกเขาใช้ได้เฉพาะในกรณีที่การแสดงออกปกติตรงกับตัวละครตัวหนึ่ง แต่นั่นก็เพียงพอสำหรับวัตถุประสงค์ของฉันเพราะฉันจะใช้มันเพื่อสิ่งต่าง ๆ เช่น ([abc], \ s, \ W, \ D)

ฉันจะคอยตรวจสอบคำถามต่อไปในกรณีที่มีผู้ใช้งานที่ดีขึ้น / เร็วขึ้น / สะอาดขึ้น / มีการใช้งานทั่วไปที่ทำงานกับนิพจน์ทั่วไปมากขึ้น


ว้าวนั่นเป็นรหัสยาว ๆ โปรดตรวจสอบคำตอบที่อัปเดตของฉันและให้ข้อเสนอแนะ ขอบคุณ
เจสันตอม่อ

การนำไปใช้งานนี้มีจุดมุ่งหมายเพื่อความเข้ากันได้อย่างสมบูรณ์กับ lastIndexOf ใน Firefox และเอ็นจิ้น SpiderMonkey JavaScript รวมถึงในหลายกรณีซึ่งเป็นกรณีขอบ [... ] ในแอปพลิเคชันในโลกแห่งความเป็นจริงคุณอาจคำนวณจากรหัสที่ซับซ้อนน้อยกว่าหากคุณไม่สนใจกรณีเหล่านั้น
Pat

ฟอร์มหน้า mozilla :-) ฉันเพิ่งเอาโค้ดโฆษณาเปลี่ยนสองบรรทัดออกจากเคสทั้งหมด เนื่องจากคำตอบอื่น ๆ สองสามข้อได้รับการอัปเดตเพื่อผ่านการทดสอบฉันจะลองเปรียบเทียบและยอมรับประสิทธิภาพสูงสุด เมื่อฉันมีเวลาทบทวนปัญหาอีกครั้ง
Pat

ฉันอัปเดตโซลูชันแล้วและขอขอบคุณข้อเสนอแนะหรือสิ่งที่ทำให้ล้มเหลว ฉันทำการเปลี่ยนแปลงในการแก้ไขปัญหาที่ทับซ้อนกันชี้ให้เห็นโดย MizardX (หวังว่า)
เจสันตอม่อ

2

ฉันต้องการregexIndexOfฟังก์ชั่นสำหรับอาร์เรย์ดังนั้นฉันจึงตั้งโปรแกรมเอง อย่างไรก็ตามฉันสงสัยว่ามันได้รับการปรับปรุง แต่ฉันคิดว่ามันควรจะทำงานได้อย่างถูกต้อง

Array.prototype.regexIndexOf = function (regex, startpos = 0) {
    len = this.length;
    for(x = startpos; x < len; x++){
        if(typeof this[x] != 'undefined' && (''+this[x]).match(regex)){
            return x;
        }
    }
    return -1;
}

arr = [];
arr.push(null);
arr.push(NaN);
arr[3] = 7;
arr.push('asdf');
arr.push('qwer');
arr.push(9);
arr.push('...');
console.log(arr);
arr.regexIndexOf(/\d/, 4);

1

ในบางกรณีคุณสามารถทำให้การค้นหาย้อนหลังของคุณง่ายขึ้นโดยใช้การแบ่ง

function regexlast(string,re){
  var tokens=string.split(re);
  return (tokens.length>1)?(string.length-tokens[tokens.length-1].length):null;
}

ปัญหานี้มีปัญหาร้ายแรงบางประการ:

  1. การจับคู่ที่ซ้อนทับกันจะไม่ปรากฏขึ้น
  2. ดัชนีที่ส่งคืนสำหรับการสิ้นสุดของการแข่งขันไม่ใช่การเริ่มต้น (ดีถ้า regex ของคุณเป็นค่าคงที่)

แต่ในด้านความสว่างมันเป็นรหัสน้อย สำหรับ regex ที่มีความยาวคงที่ซึ่งไม่สามารถซ้อนทับกันได้ (เช่น/\s\w/การค้นหาขอบเขตคำ) มันดีพอ


0

สำหรับข้อมูลที่มีการจับคู่แบบเบาบางการใช้ string.search เป็นวิธีที่เร็วที่สุดในเบราว์เซอร์ มัน re-slices สตริงแต่ละการวนซ้ำเพื่อ:

function lastIndexOfSearch(string, regex, index) {
  if(index === 0 || index)
     string = string.slice(0, Math.max(0,index));
  var idx;
  var offset = -1;
  while ((idx = string.search(regex)) !== -1) {
    offset += idx + 1;
    string = string.slice(idx + 1);
  }
  return offset;
}

สำหรับข้อมูลที่หนาแน่นฉันทำสิ่งนี้ มันซับซ้อนเมื่อเปรียบเทียบกับวิธีการดำเนินการ แต่สำหรับข้อมูลที่หนาแน่นนั้นเร็วกว่าวิธีอื่น ๆ ที่ฉันได้ลอง 2-10 เท่าและเร็วกว่าโซลูชันที่ยอมรับประมาณ 100 เท่า ประเด็นหลักคือ:

  1. มันเรียก exec บน regex ที่ผ่านไปหนึ่งครั้งเพื่อตรวจสอบว่ามีการแข่งขันหรือออกจากต้น ฉันทำสิ่งนี้โดยใช้ (? = ในวิธีที่คล้ายกัน แต่ในการตรวจสอบ IE ด้วย exec จะเร็วขึ้นอย่างมาก
  2. มันสร้างและแคช regex แก้ไขในรูปแบบ '(r) (?!. ? r) '
  3. regex ใหม่จะถูกดำเนินการและผลลัพธ์ที่ได้จากการที่ exec หรือ exec แรกจะถูกส่งกลับ;

    function lastIndexOfGroupSimple(string, regex, index) {
        if (index === 0 || index) string = string.slice(0, Math.max(0, index + 1));
        regex.lastIndex = 0;
        var lastRegex, index
        flags = 'g' + (regex.multiline ? 'm' : '') + (regex.ignoreCase ? 'i' : ''),
        key = regex.source + '$' + flags,
        match = regex.exec(string);
        if (!match) return -1;
        if (lastIndexOfGroupSimple.cache === undefined) lastIndexOfGroupSimple.cache = {};
        lastRegex = lastIndexOfGroupSimple.cache[key];
        if (!lastRegex)
            lastIndexOfGroupSimple.cache[key] = lastRegex = new RegExp('.*(' + regex.source + ')(?!.*?' + regex.source + ')', flags);
        index = match.index;
        lastRegex.lastIndex = match.index;
        return (match = lastRegex.exec(string)) ? lastRegex.lastIndex - match[1].length : index;
    };

jsPerf ของวิธีการ

ฉันไม่เข้าใจวัตถุประสงค์ของการทดสอบ สถานการณ์ที่ต้องใช้ regex นั้นเป็นไปไม่ได้ที่จะเปรียบเทียบกับการเรียกไปยัง indexOf ซึ่งฉันคิดว่าเป็นจุดเริ่มต้นของวิธีการในตอนแรก ในการทำให้การทดสอบผ่านได้เหมาะสมกว่าที่จะใช้ 'xxx + (?! x)' มากกว่าปรับวิธีการวนซ้ำของ regex


0

ดัชนีล่าสุดของ Jason Bunting ของไม่ทำงาน ฉันไม่ได้ดีที่สุด แต่ก็ใช้งานได้

//Jason Bunting's
String.prototype.regexIndexOf = function(regex, startpos) {
var indexOf = this.substring(startpos || 0).search(regex);
return (indexOf >= 0) ? (indexOf + (startpos || 0)) : indexOf;
}

String.prototype.regexLastIndexOf = function(regex, startpos) {
var lastIndex = -1;
var index = this.regexIndexOf( regex );
startpos = startpos === undefined ? this.length : startpos;

while ( index >= 0 && index < startpos )
{
    lastIndex = index;
    index = this.regexIndexOf( regex, index + 1 );
}
return lastIndex;
}

คุณช่วยให้การทดสอบที่ทำให้ฉันล้มเหลวได้หรือไม่? หากคุณพบว่าใช้งานไม่ได้ให้ระบุกรณีทดสอบทำไมเพียงแค่พูดว่า "ไม่ทำงาน" และจัดเตรียมโซลูชันที่ไม่เหมาะสม
Jason Bunting

เด็กผู้ชายฮู คุณพูดถูก ฉันควรยกตัวอย่าง น่าเสียดายที่ฉันย้ายไปจากรหัสนี้เมื่อหลายเดือนก่อนและไม่รู้ว่ากรณีใดที่ล้มเหลว : - /
อีลี

ดีนั่นคือชีวิต :)
Jason Bunting

0

ยังไม่มีวิธีดั้งเดิมที่ดำเนินการตามที่ร้องขอ

นี่คือรหัสที่ฉันใช้ มันเลียนแบบพฤติกรรมของString.prototype.indexOfและString.prototype.lastIndexOfวิธี แต่พวกเขายังยอมรับนิพจน์ทั่วไปเป็นอาร์กิวเมนต์ค้นหาในนอกจากสตริงเป็นตัวแทนของค่าที่จะค้นหา

ใช่มันค่อนข้างจะยาวเมื่อคำตอบดำเนินไปตามที่พยายามปฏิบัติตามมาตรฐานปัจจุบันใกล้เคียงที่สุดและแน่นอนว่ามีจำนวนJSDOC ที่สมเหตุสมผลความคิดเห็นอย่างไรก็ตามเมื่อย่อขนาดโค้ดจะมีเพียง 2.27k และเมื่อ gzipped สำหรับการส่งมีค่าเพียง 1,023 ไบต์

2 เมธอดที่สิ่งนี้เพิ่มให้กับString.prototype(โดยใช้Object.definePropertyหากมี):

  1. searchOf
  2. searchLastOf

มันผ่านการทดสอบทั้งหมดที่ OP โพสต์และนอกจากนี้ฉันได้ทดสอบกิจวัตรประจำวันของฉันอย่างละเอียดและได้พยายามทำให้แน่ใจว่าพวกเขาทำงานในสภาพแวดล้อมที่หลากหลาย แต่ยินดีรับข้อเสนอแนะ / ปัญหาเสมอ

/*jslint maxlen:80, browser:true */

/*
 * Properties used by searchOf and searchLastOf implementation.
 */

/*property
    MAX_SAFE_INTEGER, abs, add, apply, call, configurable, defineProperty,
    enumerable, exec, floor, global, hasOwnProperty, ignoreCase, index,
    lastIndex, lastIndexOf, length, max, min, multiline, pow, prototype,
    remove, replace, searchLastOf, searchOf, source, toString, value, writable
*/

/*
 * Properties used in the testing of searchOf and searchLastOf implimentation.
 */

/*property
    appendChild, createTextNode, getElementById, indexOf, lastIndexOf, length,
    searchLastOf, searchOf, unshift
*/

(function () {
    'use strict';

    var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1,
        getNativeFlags = new RegExp('\\/([a-z]*)$', 'i'),
        clipDups = new RegExp('([\\s\\S])(?=[\\s\\S]*\\1)', 'g'),
        pToString = Object.prototype.toString,
        pHasOwn = Object.prototype.hasOwnProperty,
        stringTagRegExp;

    /**
     * Defines a new property directly on an object, or modifies an existing
     * property on an object, and returns the object.
     *
     * @private
     * @function
     * @param {Object} object
     * @param {string} property
     * @param {Object} descriptor
     * @returns {Object}
     * @see https://goo.gl/CZnEqg
     */
    function $defineProperty(object, property, descriptor) {
        if (Object.defineProperty) {
            Object.defineProperty(object, property, descriptor);
        } else {
            object[property] = descriptor.value;
        }

        return object;
    }

    /**
     * Returns true if the operands are strictly equal with no type conversion.
     *
     * @private
     * @function
     * @param {*} a
     * @param {*} b
     * @returns {boolean}
     * @see http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.4
     */
    function $strictEqual(a, b) {
        return a === b;
    }

    /**
     * Returns true if the operand inputArg is undefined.
     *
     * @private
     * @function
     * @param {*} inputArg
     * @returns {boolean}
     */
    function $isUndefined(inputArg) {
        return $strictEqual(typeof inputArg, 'undefined');
    }

    /**
     * Provides a string representation of the supplied object in the form
     * "[object type]", where type is the object type.
     *
     * @private
     * @function
     * @param {*} inputArg The object for which a class string represntation
     *                     is required.
     * @returns {string} A string value of the form "[object type]".
     * @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.4.2
     */
    function $toStringTag(inputArg) {
        var val;
        if (inputArg === null) {
            val = '[object Null]';
        } else if ($isUndefined(inputArg)) {
            val = '[object Undefined]';
        } else {
            val = pToString.call(inputArg);
        }

        return val;
    }

    /**
     * The string tag representation of a RegExp object.
     *
     * @private
     * @type {string}
     */
    stringTagRegExp = $toStringTag(getNativeFlags);

    /**
     * Returns true if the operand inputArg is a RegExp.
     *
     * @private
     * @function
     * @param {*} inputArg
     * @returns {boolean}
     */
    function $isRegExp(inputArg) {
        return $toStringTag(inputArg) === stringTagRegExp &&
                pHasOwn.call(inputArg, 'ignoreCase') &&
                typeof inputArg.ignoreCase === 'boolean' &&
                pHasOwn.call(inputArg, 'global') &&
                typeof inputArg.global === 'boolean' &&
                pHasOwn.call(inputArg, 'multiline') &&
                typeof inputArg.multiline === 'boolean' &&
                pHasOwn.call(inputArg, 'source') &&
                typeof inputArg.source === 'string';
    }

    /**
     * The abstract operation throws an error if its argument is a value that
     * cannot be converted to an Object, otherwise returns the argument.
     *
     * @private
     * @function
     * @param {*} inputArg The object to be tested.
     * @throws {TypeError} If inputArg is null or undefined.
     * @returns {*} The inputArg if coercible.
     * @see https://goo.gl/5GcmVq
     */
    function $requireObjectCoercible(inputArg) {
        var errStr;

        if (inputArg === null || $isUndefined(inputArg)) {
            errStr = 'Cannot convert argument to object: ' + inputArg;
            throw new TypeError(errStr);
        }

        return inputArg;
    }

    /**
     * The abstract operation converts its argument to a value of type string
     *
     * @private
     * @function
     * @param {*} inputArg
     * @returns {string}
     * @see https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tostring
     */
    function $toString(inputArg) {
        var type,
            val;

        if (inputArg === null) {
            val = 'null';
        } else {
            type = typeof inputArg;
            if (type === 'string') {
                val = inputArg;
            } else if (type === 'undefined') {
                val = type;
            } else {
                if (type === 'symbol') {
                    throw new TypeError('Cannot convert symbol to string');
                }

                val = String(inputArg);
            }
        }

        return val;
    }

    /**
     * Returns a string only if the arguments is coercible otherwise throws an
     * error.
     *
     * @private
     * @function
     * @param {*} inputArg
     * @throws {TypeError} If inputArg is null or undefined.
     * @returns {string}
     */
    function $onlyCoercibleToString(inputArg) {
        return $toString($requireObjectCoercible(inputArg));
    }

    /**
     * The function evaluates the passed value and converts it to an integer.
     *
     * @private
     * @function
     * @param {*} inputArg The object to be converted to an integer.
     * @returns {number} If the target value is NaN, null or undefined, 0 is
     *                   returned. If the target value is false, 0 is returned
     *                   and if true, 1 is returned.
     * @see http://www.ecma-international.org/ecma-262/5.1/#sec-9.4
     */
    function $toInteger(inputArg) {
        var number = +inputArg,
            val = 0;

        if ($strictEqual(number, number)) {
            if (!number || number === Infinity || number === -Infinity) {
                val = number;
            } else {
                val = (number > 0 || -1) * Math.floor(Math.abs(number));
            }
        }

        return val;
    }

    /**
     * Copies a regex object. Allows adding and removing native flags while
     * copying the regex.
     *
     * @private
     * @function
     * @param {RegExp} regex Regex to copy.
     * @param {Object} [options] Allows specifying native flags to add or
     *                           remove while copying the regex.
     * @returns {RegExp} Copy of the provided regex, possibly with modified
     *                   flags.
     */
    function $copyRegExp(regex, options) {
        var flags,
            opts,
            rx;

        if (options !== null && typeof options === 'object') {
            opts = options;
        } else {
            opts = {};
        }

        // Get native flags in use
        flags = getNativeFlags.exec($toString(regex))[1];
        flags = $onlyCoercibleToString(flags);
        if (opts.add) {
            flags += opts.add;
            flags = flags.replace(clipDups, '');
        }

        if (opts.remove) {
            // Would need to escape `options.remove` if this was public
            rx = new RegExp('[' + opts.remove + ']+', 'g');
            flags = flags.replace(rx, '');
        }

        return new RegExp(regex.source, flags);
    }

    /**
     * The abstract operation ToLength converts its argument to an integer
     * suitable for use as the length of an array-like object.
     *
     * @private
     * @function
     * @param {*} inputArg The object to be converted to a length.
     * @returns {number} If len <= +0 then +0 else if len is +INFINITY then
     *                   2^53-1 else min(len, 2^53-1).
     * @see https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
     */
    function $toLength(inputArg) {
        return Math.min(Math.max($toInteger(inputArg), 0), MAX_SAFE_INTEGER);
    }

    /**
     * Copies a regex object so that it is suitable for use with searchOf and
     * searchLastOf methods.
     *
     * @private
     * @function
     * @param {RegExp} regex Regex to copy.
     * @returns {RegExp}
     */
    function $toSearchRegExp(regex) {
        return $copyRegExp(regex, {
            add: 'g',
            remove: 'y'
        });
    }

    /**
     * Returns true if the operand inputArg is a member of one of the types
     * Undefined, Null, Boolean, Number, Symbol, or String.
     *
     * @private
     * @function
     * @param {*} inputArg
     * @returns {boolean}
     * @see https://goo.gl/W68ywJ
     * @see https://goo.gl/ev7881
     */
    function $isPrimitive(inputArg) {
        var type = typeof inputArg;

        return type === 'undefined' ||
                inputArg === null ||
                type === 'boolean' ||
                type === 'string' ||
                type === 'number' ||
                type === 'symbol';
    }

    /**
     * The abstract operation converts its argument to a value of type Object
     * but fixes some environment bugs.
     *
     * @private
     * @function
     * @param {*} inputArg The argument to be converted to an object.
     * @throws {TypeError} If inputArg is not coercible to an object.
     * @returns {Object} Value of inputArg as type Object.
     * @see http://www.ecma-international.org/ecma-262/5.1/#sec-9.9
     */
    function $toObject(inputArg) {
        var object;

        if ($isPrimitive($requireObjectCoercible(inputArg))) {
            object = Object(inputArg);
        } else {
            object = inputArg;
        }

        return object;
    }

    /**
     * Converts a single argument that is an array-like object or list (eg.
     * arguments, NodeList, DOMTokenList (used by classList), NamedNodeMap
     * (used by attributes property)) into a new Array() and returns it.
     * This is a partial implementation of the ES6 Array.from
     *
     * @private
     * @function
     * @param {Object} arrayLike
     * @returns {Array}
     */
    function $toArray(arrayLike) {
        var object = $toObject(arrayLike),
            length = $toLength(object.length),
            array = [],
            index = 0;

        array.length = length;
        while (index < length) {
            array[index] = object[index];
            index += 1;
        }

        return array;
    }

    if (!String.prototype.searchOf) {
        /**
         * This method returns the index within the calling String object of
         * the first occurrence of the specified value, starting the search at
         * fromIndex. Returns -1 if the value is not found.
         *
         * @function
         * @this {string}
         * @param {RegExp|string} regex A regular expression object or a String.
         *                              Anything else is implicitly converted to
         *                              a String.
         * @param {Number} [fromIndex] The location within the calling string
         *                             to start the search from. It can be any
         *                             integer. The default value is 0. If
         *                             fromIndex < 0 the entire string is
         *                             searched (same as passing 0). If
         *                             fromIndex >= str.length, the method will
         *                             return -1 unless searchValue is an empty
         *                             string in which case str.length is
         *                             returned.
         * @returns {Number} If successful, returns the index of the first
         *                   match of the regular expression inside the
         *                   string. Otherwise, it returns -1.
         */
        $defineProperty(String.prototype, 'searchOf', {
            enumerable: false,
            configurable: true,
            writable: true,
            value: function (regex) {
                var str = $onlyCoercibleToString(this),
                    args = $toArray(arguments),
                    result = -1,
                    fromIndex,
                    match,
                    rx;

                if (!$isRegExp(regex)) {
                    return String.prototype.indexOf.apply(str, args);
                }

                if ($toLength(args.length) > 1) {
                    fromIndex = +args[1];
                    if (fromIndex < 0) {
                        fromIndex = 0;
                    }
                } else {
                    fromIndex = 0;
                }

                if (fromIndex >= $toLength(str.length)) {
                    return result;
                }

                rx = $toSearchRegExp(regex);
                rx.lastIndex = fromIndex;
                match = rx.exec(str);
                if (match) {
                    result = +match.index;
                }

                return result;
            }
        });
    }

    if (!String.prototype.searchLastOf) {
        /**
         * This method returns the index within the calling String object of
         * the last occurrence of the specified value, or -1 if not found.
         * The calling string is searched backward, starting at fromIndex.
         *
         * @function
         * @this {string}
         * @param {RegExp|string} regex A regular expression object or a String.
         *                              Anything else is implicitly converted to
         *                              a String.
         * @param {Number} [fromIndex] Optional. The location within the
         *                             calling string to start the search at,
         *                             indexed from left to right. It can be
         *                             any integer. The default value is
         *                             str.length. If it is negative, it is
         *                             treated as 0. If fromIndex > str.length,
         *                             fromIndex is treated as str.length.
         * @returns {Number} If successful, returns the index of the first
         *                   match of the regular expression inside the
         *                   string. Otherwise, it returns -1.
         */
        $defineProperty(String.prototype, 'searchLastOf', {
            enumerable: false,
            configurable: true,
            writable: true,
            value: function (regex) {
                var str = $onlyCoercibleToString(this),
                    args = $toArray(arguments),
                    result = -1,
                    fromIndex,
                    length,
                    match,
                    pos,
                    rx;

                if (!$isRegExp(regex)) {
                    return String.prototype.lastIndexOf.apply(str, args);
                }

                length = $toLength(str.length);
                if (!$strictEqual(args[1], args[1])) {
                    fromIndex = length;
                } else {
                    if ($toLength(args.length) > 1) {
                        fromIndex = $toInteger(args[1]);
                    } else {
                        fromIndex = length - 1;
                    }
                }

                if (fromIndex >= 0) {
                    fromIndex = Math.min(fromIndex, length - 1);
                } else {
                    fromIndex = length - Math.abs(fromIndex);
                }

                pos = 0;
                rx = $toSearchRegExp(regex);
                while (pos <= fromIndex) {
                    rx.lastIndex = pos;
                    match = rx.exec(str);
                    if (!match) {
                        break;
                    }

                    pos = +match.index;
                    if (pos <= fromIndex) {
                        result = pos;
                    }

                    pos += 1;
                }

                return result;
            }
        });
    }
}());

(function () {
    'use strict';

    /*
     * testing as follow to make sure that at least for one character regexp,
     * the result is the same as if we used indexOf
     */

    var pre = document.getElementById('out');

    function log(result) {
        pre.appendChild(document.createTextNode(result + '\n'));
    }

    function test(str) {
        var i = str.length + 2,
            r,
            a,
            b;

        while (i) {
            a = str.indexOf('a', i);
            b = str.searchOf(/a/, i);
            r = ['Failed', 'searchOf', str, i, a, b];
            if (a === b) {
                r[0] = 'Passed';
            }

            log(r);
            a = str.lastIndexOf('a', i);
            b = str.searchLastOf(/a/, i);
            r = ['Failed', 'searchLastOf', str, i, a, b];
            if (a === b) {
                r[0] = 'Passed';
            }

            log(r);
            i -= 1;
        }
    }

    /*
     * Look for the a among the xes
     */

    test('xxx');
    test('axx');
    test('xax');
    test('xxa');
    test('axa');
    test('xaa');
    test('aax');
    test('aaa');
}());
<pre id="out"></pre>


0

หากคุณกำลังมองหาการค้นหา lastIndex ที่ง่ายมากด้วย RegExp และไม่สนใจว่ามันจะเลียนแบบ lastIndexOf ไปจนถึงรายละเอียดสุดท้ายนี่อาจดึงดูดความสนใจของคุณ

ฉันเพียงแค่ย้อนกลับสตริงและลบดัชนีการเกิดครั้งแรกจากความยาว - 1 มันเกิดขึ้นผ่านการทดสอบของฉัน แต่ฉันคิดว่าอาจมีปัญหาประสิทธิภาพการทำงานกับสายยาว

interface String {
  reverse(): string;
  lastIndex(regex: RegExp): number;
}

String.prototype.reverse = function(this: string) {
  return this.split("")
    .reverse()
    .join("");
};

String.prototype.lastIndex = function(this: string, regex: RegExp) {
  const exec = regex.exec(this.reverse());
  return exec === null ? -1 : this.length - 1 - exec.index;
};

0

ฉันใช้ String.prototype.match(regex)ซึ่งส่งกลับอาร์เรย์สตริงของการแข่งขันพบทั้งหมดของที่กำหนดregexในสตริง (ข้อมูลเพิ่มเติมดูที่นี่ ):

function getLastIndex(text, regex, limit = text.length) {
  const matches = text.match(regex);

  // no matches found
  if (!matches) {
    return -1;
  }

  // matches found but first index greater than limit
  if (text.indexOf(matches[0] + matches[0].length) > limit) {
    return -1;
  }

  // reduce index until smaller than limit
  let i = matches.length - 1;
  let index = text.lastIndexOf(matches[i]);
  while (index > limit && i >= 0) {
    i--;
    index = text.lastIndexOf(matches[i]);
  }
  return index > limit ? -1 : index;
}

// expect -1 as first index === 14
console.log(getLastIndex('First Sentence. Last Sentence. Unfinished', /\. /g, 10));

// expect 29
console.log(getLastIndex('First Sentence. Last Sentence. Unfinished', /\. /g));


0
var mystring = "abc ab a";
var re  = new RegExp("ab"); // any regex here

if ( re.exec(mystring) != null ){ 
   alert("matches"); // true in this case
}

ใช้นิพจน์ปกติมาตรฐาน:

var re  = new RegExp("^ab");  // At front
var re  = new RegExp("ab$");  // At end
var re  = new RegExp("ab(c|d)");  // abc or abd

-2

ในขณะที่คุณกำลังมองหาการจับคู่ตำแหน่งของตัวละคร regex อาจเป็นไปได้มากเกินไป

ฉันคิดว่าทุกสิ่งที่คุณต้องการคือ "ค้นหาตัวอักษรตัวแรกของตัวละครเหล่านี้" แทนที่จะค้นหาตัวอักษรตัวแรกเหล่านี้

แน่นอนว่านี่เป็นคำตอบที่ง่าย แต่ทำในสิ่งที่คำถามของคุณทำแม้ว่าจะไม่มีส่วน regex (เพราะคุณไม่ได้อธิบายว่าทำไมมันต้องเป็น regex โดยเฉพาะ)

function mIndexOf( str , chars, offset )
{
   var first  = -1; 
   for( var i = 0; i < chars.length;  i++ )
   {
      var p = str.indexOf( chars[i] , offset ); 
      if( p < first || first === -1 )
      {
           first = p;
      }
   }
   return first; 
}
String.prototype.mIndexOf = function( chars, offset )
{
   return mIndexOf( this, chars, offset ); # I'm really averse to monkey patching.  
};
mIndexOf( "hello world", ['a','o','w'], 0 );
>> 4 
mIndexOf( "hello world", ['a'], 0 );
>> -1 
mIndexOf( "hello world", ['a','o','w'], 4 );
>> 4
mIndexOf( "hello world", ['a','o','w'], 5 );
>> 6
mIndexOf( "hello world", ['a','o','w'], 7 );
>> -1 
mIndexOf( "hello world", ['a','o','w','d'], 7 );
>> 10
mIndexOf( "hello world", ['a','o','w','d'], 10 );
>> 10
mIndexOf( "hello world", ['a','o','w','d'], 11 );
>> -1

เพียงแค่ความคิดเห็นเกี่ยวกับการปะแก้ลิง - ในขณะที่ฉันตระหนักถึงปัญหาของมัน - คุณคิดว่าการทำให้สกปรกเนมสเปซทั่วโลกนั้นดีกว่าไหม มันไม่เหมือนความขัดแย้งของสัญลักษณ์ในกรณีทั้งสองไม่สามารถเกิดขึ้นได้และโดยทั่วไปจะมีการปรับโครงสร้าง / ซ่อมแซมในลักษณะเดียวกันหากเกิดปัญหาขึ้น
Peter Bailey

ฉันต้องการค้นหา \ s และในบางกรณี \ W และหวังว่าฉันไม่จำเป็นต้องระบุความเป็นไปได้ทั้งหมด
Pat

BaileyP: คุณสามารถแก้ไขปัญหานี้ได้โดยไม่มีมลภาวะเนมสเปซส่วนกลางเช่น: ดู jQuery ใช้โมเดลนั้น วัตถุหนึ่งชิ้นสำหรับโครงการสิ่งของของคุณเข้าไปข้างใน Mootools ทิ้งรสชาติที่ไม่ดีไว้ในปากของฉัน
Kent Fredric

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