【问题标题】:How to increment/decrement a unicode String in Java?如何在 Java 中增加/减少 unicode 字符串?
【发布时间】:2012-10-10 20:36:38
【问题描述】:

如何实现给定字符串 A 生成字符串 B 的函数 increment(string) 其中:

  1. B > A(使用 Java 的 compareTo 逻辑)
  2. 存在 NO C,其中 B > C > A

对于给定字符串 A 产生字符串 B 的减量(字符串)也是如此:

  1. B
  2. 存在 NO C 其中 B

编辑

正如 cmets 中所指出的,如果没有一些限制,这个问题是不可能回答的。限制是你不能在字符串中追加/删除新字符,除非它是为了处理流量不足/溢出。

【问题讨论】:

  • 我认为这个问题缺少一个警告。即A和B的长度应该相同,否则这个问题是不可能完全回答的。需要注意的是,这个问题简直太难了。一个额外的警告是字符串只能由 ASCII 字母数字字符组成,这将使它成为一个合理的家庭作业问题。
  • @Dunes:我认为没有任何理由将其限制为 ASCII 字母数字字符。请注意,compareTo 没有考虑语言环境或类似的东西。它甚至不处理代理对 - 斜线 - 完整的 Unicode 代码点。这是严格两个无符号 16 位整数序列的字典比较。
  • 哦,哇,我没有意识到编程语言有多么滥用词典这个术语。经过研究,我会说 Java 根据 UTF-16 代码单元的数字顺序进行排序。这意味着排序甚至与任何其他 unicode 编码方案都不一致。词典顺序意味着使用字典或词典,这意味着给定自然语言的字母顺序。很高兴我能早点知道这一点。感谢您指出@ruakh
  • @Dunes:这不仅仅是这个术语的编程用途,而是数学用途。 (参见the Wikipedia article on "lexicographical order"。)编程对数学的唯一补充是,在数学中,字典顺序通常是在一组等长序列(尤其是有序对)上定义的,而在编程中,我们将其概括为允许变量-length 序列,通过说(例如)"a" 小于"ab"。 (当然,在这方面,我们与常规字典顺序一致。)
  • 我认为在编程语言中谈论字符串时这个词被滥用了。词典编纂是关于编译词典(用于自然语言)。在数学中,由于抽象层,您可以摆脱与自然语言的联系。但是,当谈到明确表示自然语言字母表的数据类型时,您需要更具体地进行比较。见鬼,即使在文档细节中也不清楚是否正在执行代码单元或代码点比较。

标签: java string algorithm unicode


【解决方案1】:

增量很简单:B = A + "\u0000"

递减是不可能的;例如,小于"Y" 的最大字符串是"X\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF\uFFFF..."

【讨论】:

  • +1 用于跳出框框思考。当我读到这个问题时,我真的很困惑,准备尖叫“不可能”。
  • 这是原题的正确答案,但我对原题加了限制。
  • @Drew:您修改后的问题非常模糊。我认为你至少需要给出五六个例子,包括边缘情况。
【解决方案2】:

我想你可以把增量写成:

    str = str.substring(0, str.length()-1)+((char)(str.charAt(str.length()-1)+1));

并递减为:

    str = str.substring(0, str.length()-1)+((char)(str.charAt(str.length()-1)-1));

这里一定要处理边界条件,即在递增期间,如果您的字符串最高,而在递减期间,您的字符串是最小的。

【讨论】:

    【解决方案3】:

    试试这个:(编辑修复了一些错误,编辑 2:测试工作,但比较失败)

    import static org.junit.Assert.*;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    class Ids {
        Ids(char min,char max) {
            this.min=min;
            this.max=max;
            n=max-min+1;
        }
        String inc(String s) {
            if(print)
                System.out.println("inc "+s);
            String t="";
            char c=s.charAt(s.length()-1);
            char o=c==max?min:(char)(c+1);
            boolean carry=o==min;
            t+=o;
            for(int i=s.length()-2;i>=0;i--) {
                c=s.charAt(i);
                if(carry) {
                    o=c==max?min:(char)(c+1);
                    carry=o==min;
                } else o=c;
                t+=o;
            }
            if(carry)
                t+=min;
            t=reverse(t);
            if(print)
                System.out.println("inc returns "+t);
            int compare=s.compareTo(t);
            if(compare!=-1)
                System.out.println("compare fails: "+s+"<>"+t+" returns "+compare);
            return t;
        }
        private static String reverse(String t) {
            String t2="";
            for(int i=0;i<t.length();i++)
                t2+=t.charAt(t.length()-1-i);
            return t2;
        }
        String dec(String s) {
            if(print)
                System.out.println("dec "+s);
            String t="";
            char c=s.charAt(s.length()-1);
            if(c==min&&s.length()==1)
                return null;
            char o=c==min?max:(char)(c-1);
            boolean borrow=o==max;
            t+=o;
            if(print)
                System.out.println("last character, t="+t);
            for(int i=s.length()-2;i>=0;i--) {
                c=s.charAt(i);
                if(print)
                    System.out.println("in loop, c="+c);
                if(borrow) {
                    if(c==min) {
                        o=max;
                        borrow=true;
                    } else {
                        o=--c;
                        borrow=false;
                    }
                    // o=c==min?max:(char)(c-1);
                    // borrow=o==max;
                } else o=c;
                if(print)
                    System.out.println("in loop, adding: "+o);
                t+=o;
                if(print)
                    System.out.println("in loop, t="+t);
            }
            if(borrow)
                t=t.substring(0,t.length()-1);
            t=reverse(t);
            if(print)
                System.out.println("dec returns "+t);
            int compare=s.compareTo(t);
            if(compare!=1)
                System.out.println("compare fails: "+s+"<>"+t+" returns "+compare);
            return t;
        }
        void run(String s) {
            String i=inc(s);
            String d=dec(s);
            System.out.println(d+"<"+s+"<"+i);
        }
        void run() {
            print();
            run("b");
            run("c");
            run("y");
            run("z");
        }
        public static void main(String[] args) {
            new Ids('a','z').run();
        }
        void print() {
            System.out.println("min="+min+", max="+max+",range="+n);
        }
        static boolean print;
        final char min,max;
        final int n;
    }
    public class So12827926TestCase {
        @Before public void setUp() throws Exception {
            Ids.print=false;
        }
        @After public void tearDown() throws Exception {
            Ids.print=false;
        }
        @Test public void testIncDecOnOneCharacter() {
            for(char c=ids.min;c<ids.max;c++) {
                String original=""+(char)(c);
                String expected=""+(char)(c+1);
                String actual=ids.inc(""+(char)c);
                assertEquals(expected,actual);
                String duplicate=ids.dec(expected);
                assertEquals(original,duplicate);
            }
        }
        @Test public void testDecIncOnOneCharacter() {
            for(char c=(char)(ids.min+1);c<=ids.max;c++) {
                String original=""+(char)(c);
                String expected=""+(char)(c-1);
                String actual=ids.dec(""+(char)c);
                assertEquals(expected,actual);
                String duplicate=ids.inc(expected);
                assertEquals(original,duplicate);
            }
        }
        @Test public void testIncDecEdgeCaseOnOneCharacter() {
            String original=""+ids.max;
            String expected=""+ids.min+ids.min;
            String actual=ids.inc(original);
            assertEquals(expected,actual);
            String duplicate=ids.dec(expected);
            assertEquals(original,duplicate);
        }
        @Test public void testIncEdgeCaseOnTwoCharacters() {
            String original=""+ids.min+ids.min;
            String expected=""+ids.min+(char)(ids.min+1);
            String actual=ids.inc(original);
            assertEquals(expected,actual);
        }
        @Test public void testDecIncEdgeCaseOnOneCharacter() {
            String original=""+ids.min;
            String expected=null;
            String actual=ids.dec(original);
            assertEquals(expected,actual);
            if(expected!=null) {
                String duplicate=ids.inc(expected);
                assertEquals(original,duplicate);
            }
        }
        @Test public void testIncDecEdgeCaseOnTwoCharacters() {
            String original=""+ids.min+ids.max;
            String expected=""+(char)(ids.min+1)+ids.min;
            String actual=ids.inc(original);
            assertEquals(expected,actual);
            String duplicate=ids.dec(expected);
            assertEquals(original,duplicate);
        }
        @Test public void testDecIncEdgeCaseOnTwoCharacters() {
            String original=""+ids.max+ids.min;
            String expected=""+(char)(ids.max-1)+ids.max;
            String actual=ids.dec(original);
            assertEquals(expected,actual);
            String duplicate=ids.inc(expected);
            assertEquals(original,duplicate);
        }
        @Test public void testIncDecEdgeCaseOnThreeCharacters() {
            String original=""+ids.min+ids.max+ids.max;
            String expected=""+(char)(ids.min+1)+ids.min+ids.min;
            String actual=ids.inc(original);
            assertEquals(expected,actual);
            String duplicate=ids.dec(expected);
            assertEquals(original,duplicate);
        }
        @Test public void testDecIncEdgeCaseOnThreeCharacters() {
            String original=""+ids.max+ids.min+ids.min;
            String expected=""+(char)(ids.max-1)+ids.max+ids.max;
            String actual=ids.dec(original);
            assertEquals(expected,actual);
            String duplicate=ids.inc(expected);
            assertEquals(original,duplicate);
        }
        @Test public void testDecIntForSomeEdgeCases() {
            Ids ids=new Ids('a','z'); 
            for(int i=0;i<originals.length;i++) {
                String original=originals[i];
                String expected=expecteds[i];
                String actual=ids.dec(original);
                assertEquals(expected,actual);
                String duplicate=ids.inc(expected);
                assertEquals(original,duplicate);
            }
        }
        @Test public void testIncDecForSomeEdgeCases() {
            Ids ids=new Ids('a','z'); 
            for(int i=0;i<originals.length;i++) {
                String original=expecteds[i];
                String expected=originals[i];
                String actual=ids.inc(original);
                assertEquals(expected,actual);
                String duplicate=ids.dec(expected);
                assertEquals(original,duplicate);
            }
        }
        @Test public void testInc() {
            Ids ids=new Ids('a','z'); 
            String start=""+ids.min,s=start;
            for(int i=0;i<ids.n-1;i++) 
                s=ids.inc(s);
            assertEquals(""+ids.max,s);
        }
        @Test public void testDec() {
            Ids ids=new Ids('a','z'); 
            String start=""+ids.max,s=start;
            for(int i=0;i<ids.n-1;i++) 
                s=ids.dec(s);
            assertEquals(""+ids.min,s);
        }
        Ids ids=new Ids('a','b');
        // swap these, they will make more sense that way.
        static final String[] originals=new String[]{"baa","caa","daa","xaa","yaa","zaa"};
        static final String[] expecteds=new String[]{"azz","bzz","czz","wzz","xzz","yzz"};
    }
    

    【讨论】:

    • 当前在减少 3 个字符边缘情况时失败
    • 现在通过所有测试,但比较失败
    【解决方案4】:

    就像你对数字所做的那样。例如,取一个号码ABCD。通过将D 增加1 可以找到下一个数字。但如果这导致D 变为0,则必须增加C。等等。将字符串视为数字,其中每个数字实际上是一个 16 位值。减少的方法相同。 如何做到这一点的技术部分掌握在您手中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-11
      • 2016-02-18
      • 2012-10-21
      • 2011-04-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多